AHOI2013 差异


方法1:SA

先板个后缀数组(带 \(height\) 不带 \(st\) 表),用单调队列递推每个后缀 \(sa_i\) 对答案的贡献,求和,用定值减之。

#include <bits/stdc++.h>
using namespace std; //Start
typedef long long ll;
typedef double db;
#define mp(a,b) make_pair(a,b)
#define x first
#define y second
#define b(a) a.begin()
#define e(a) a.end()
#define sz(a) int((a).size())
#define pb(a) push_back(a)
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f; //Data
const int N=5e5;
int n;
char s[N+7]; //SuffixArray
int m,c[N+7],tp[N+7],rk[N+7],sa[N+7],h[N+7];
void csort(){
for(int i=0;i<=m;i++) c[i]=0;
for(int i=1;i<=n;i++) c[rk[i]]++;
for(int i=1;i<=m;i++) c[i]+=c[i-1];
for(int i=n;i>=1;i--) sa[c[rk[tp[i]]]--]=tp[i];
}
void build(){
for(int i=1;i<=n;i++) rk[i]=s[i],tp[i]=i;
m=128,csort();
for(int w=1,p=1,i;p<n;w<<=1,m=p){
for(p=0,i=n-w+1;i<=n;i++) tp[++p]=i;
for(i=1;i<=n;i++)if(sa[i]>w) tp[++p]=sa[i]-w;
csort(),swap(rk,tp),rk[sa[1]]=p=1;
for(i=2;i<=n;rk[sa[i]]=p,i++)
if(tp[sa[i]]!=tp[sa[i-1]]||tp[sa[i]+w]!=tp[sa[i-1]+w]) p++;
}
for(int i=1,j,k=0;i<=n;h[rk[i++]]=k)
for(k=k?k-1:k,j=sa[rk[i]-1];s[i+k]==s[j+k];k++);
} //Main
int main(){
scanf("%s",&s[1]);
n=strlen(&s[1]),build();
vector<int> q(n+7); int lst=0,qc=0;
vector<ll> f(n+7); ll res=0;
for(int i=1;i<=n;i++){
while(qc&&h[q[qc]]>h[i]) qc--;
int j=qc?q[qc]:lst;
res+=(f[i]=f[j]+1ll*(i-j)*h[i]);
if(!h[i]) lst=i;
else q[++qc]=i;
}
for(int i=1;i<=n;i++)
printf("%d ",sa[i]);puts("");
for(int i=1;i<=n;i++)
printf("%d ",h[i]);puts("");
for(int i=1;i<=n;i++)
printf("%lld ",f[i]);puts("");
printf("%lld\n",1ll*(n-1)*n*(n+1)/2-res*2);
return 0;
}

方法2:SAM

注意到这个式子是 \(\tt SAM\) \(\bf parent~tree\) 树上两点的距离,计算每条边的贡献和即可。

#include <bits/stdc++.h>
using namespace std; //Start
typedef long long ll;
typedef double db;
#define mp(a,b) make_pair(a,b)
#define x first
#define y second
#define b(a) a.begin()
#define e(a) a.end()
#define sz(a) int((a).size())
#define pb(a) push_back(a)
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f; //Data
const int N=5e5;
int n;
char s[N+7];
ll ans; //SuffixAutomata
const int T=(N<<1);
int cnt=1,en=1,ch[T+7][26],fa[T+7],dep[T+7],sz[T+7];
int c[T+7],q[T+7];
void insert(int c){
int p=en,np=++cnt;
dep[en=np]=dep[p]+1;
for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;
if(!p) fa[np]=1;
else {
int q=ch[p][c];
if(dep[q]==dep[p]+1) fa[np]=q;
else {
int nq=++cnt;
dep[nq]=dep[p]+1;
memcpy(ch[nq],ch[q],sizeof ch[q]);
fa[nq]=fa[q],fa[q]=fa[np]=nq;
for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
}
}
sz[np]=1;
}
void run(){
for(int i=1;i<=cnt;i++) c[i]=0;
for(int i=1;i<=cnt;i++) c[dep[i]]++;
for(int i=1;i<=cnt;i++) c[i]+=c[i-1];
for(int i=1;i<=cnt;i++) q[c[dep[i]]--]=i;
for(int i=cnt;i>=1;i--){
int p=q[i];
sz[fa[p]]+=sz[p];
ans+=1ll*(dep[p]-dep[fa[p]])*sz[p]*(n-sz[p]);
}
} //Main
int main(){
scanf("%s",&s[1]),n=strlen(&s[1]);
for(int i=1;i<=n;i++) insert(s[i]-'a');
run();
printf("%lld\n",ans);
return 0;
}

祝大家学习愉快!

笔记-AHOI2013 差异的更多相关文章

  1. BZOJ 3238: [Ahoi2013]差异 [后缀数组 单调栈]

    3238: [Ahoi2013]差异 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 2326  Solved: 1054[Submit][Status ...

  2. bzoj 3238 Ahoi2013 差异

    3238: [Ahoi2013]差异 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 2357  Solved: 1067[Submit][Status ...

  3. BZOJ 3238: [Ahoi2013]差异 [后缀自动机]

    3238: [Ahoi2013]差异 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 2512  Solved: 1140[Submit][Status ...

  4. BZOJ_3238_[Ahoi2013]差异_后缀自动机

    BZOJ_3238_[Ahoi2013]差异_后缀自动机 Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 Sample Input cacao Sam ...

  5. BZOJ_3238_[Ahoi2013]差异_后缀数组+单调栈

    BZOJ_3238_[Ahoi2013]差异_后缀数组+单调栈 Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 Sample Input cacao ...

  6. 【LG4248】[AHOI2013]差异

    [LG4248][AHOI2013]差异 题面 洛谷 题解 后缀数组版做法戳我 我们将原串\(reverse\),根据后缀自动机的性质,两个后缀的\(lcp\)一定是我们在反串后两个前缀的\(lca\ ...

  7. 【BZOJ3238】[AHOI2013]差异

    [BZOJ3238][AHOI2013]差异 题面 给定字符串\(S\),令\(T_i\)表示以它从第\(i\)个字符开始的后缀.求 \[ \sum_{1\leq i<j\leq n}len(T ...

  8. P4248 [AHOI2013]差异 解题报告

    P4248 [AHOI2013]差异 题目描述 给定一个长度为 \(n\) 的字符串 \(S\),令 \(T_i\) 表示它从第 \(i\) 个字符开始的后缀.求 \[\displaystyle \s ...

  9. 【BZOJ 3238】 3238: [Ahoi2013]差异(SAM)

    3238: [Ahoi2013]差异 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 3047  Solved: 1375 Description In ...

随机推荐

  1. switch,case语句易误区

    switch case 语句语法格式如下: switch(expression){ case value : //语句 break; //可选 case value : //语句 break; //可 ...

  2. 没找到Wkhtmltopdf,报表会被显示为html

    windows10 odoo 打印报表时提示 没找到Wkhtmltopdf,报表会被显示为html 现象 原因 没有安装Wkhtmltopdf,没有配置环境变量,odoo在电脑系统中找不到Wkhtml ...

  3. python + selenium 搭建环境步骤

    介绍在windows下,selenium python的安装以及配置.1.首先要下载必要的安装工具. 下载python,我安装的python3.0版本,根据你自己的需要安装 下载setuptools ...

  4. [LeetCode题解]109. 有序链表转换二叉搜索树 | 快慢指针 + 递归

    题目描述 给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树. 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1. 示例: 给定的有序链表: ...

  5. macbook上安装虚拟机软件如何操作?

    很多用户都不太熟悉苹果系统,用惯了Windows之后再过渡到MacOS难免会有些不习惯.为了使我们又可以用回那些熟悉的Windows应用,比较常见的办法就是安装macbook虚拟机.下面小编就教大家一 ...

  6. FL studio系列教程(十一):FL Studio中如何混音

    要想得到"商业"品质的声音,我们就要学会混音.混音就是声音从乐器通道到路由到混音器.混音器中可以设置电平并添加各种效果,比如,添加混响.合唱以及延迟等等,这就是所谓的混音.那么FL ...

  7. 【PUPPETEER】初探之原生frame切换(四)

    一.知识点 page.frames() 使用frame.url() 获取framed的url x.getAttribute('x') 获取元素内值 二.实例 问:什么是iframe? 答:iframe ...

  8. C#(二)基础篇—操作符

    2020-12-02 本随笔为个人复习巩固知识用,多从书上总结与理解得来,如有错误麻烦指正 1.数学操作符 int a=2,b=3,c=0; float d=0; c=a+b; //c=5 c++; ...

  9. Python爬虫合集:花6k学习爬虫,终于知道爬虫能干嘛了

    爬虫Ⅰ:爬虫的基础知识 爬虫的基础知识使用实例.应用技巧.基本知识点总结和需要注意事项 爬虫初始: 爬虫: + Request + Scrapy 数据分析+机器学习 + numpy,pandas,ma ...

  10. SSM之Spring框架--->>墨盒案例

    分析: 程序中包括打印机(Printer).墨盒(Ink).和纸张(Paper).三类组件 首先创建一个新项目文件Spring_Box 我们来定义墨盒和纸张的接口类 墨盒接口Ink.java文件内容如 ...