bzoj 3238: [Ahoi2013]差异
2015-09-08 13:07
246 查看
Description
~~~一个长度为 NN 的字符串 SS ,令 TiT_i 表示它从第 ii 个字符开始的后缀。求:∑1≤i<j≤Nlen(Ti)+len(Tj)−2∗lcp(Ti,Tj)\sum_{1\leq i
~~~其中,len(a)len(a)表示aa的长度,lcp(a,b)lcp(a,b) 表示a,ba,b的最长公共前缀长度。
~~~
~~~
~~~
Solution:
~~~首先我们可以很快算出前面两个 lenlen 的答案,所以只需减去 2∗lcp(Ti,Tj)2*lcp(T_i,T_j) 。~~~用后缀自动机构建出后缀树,然后在后缀树上 dpdp ,记录一个 Size(x)Size(x) 表示后缀树上以节点 xx 为根的子树里面有多少个后缀节点。然后一次遍历子树,对于一个子树 uu ,ans−=depth∗Size[u]∗Size[cnt]∗2,Size[cnt]+=Size[u]ans-=depth*Size[u]*Size[cnt]*2,Size[cnt]+=Size[u] 。
~~~最后如果节点 xx 也是一个后缀节点,那么ans−=depth∗Size[cnt]∗2,Size[cnt]++ans-=depth*Size[cnt]*2,Size[cnt]++
~~~
~~~
~~~
Code:
#include <cstdio> #include <cmath> #include <cstring> #include <cstdlib> #include <algorithm> #include <iostream> using namespace std; char str[500010]="\0"; struct sam { int ch[26]; int lenth; int fail; }pot[1000010]={{{0},0,0}}; int New[500010]={0}; int pp=0; int First[1000010]={0}; int N; struct bian_ { int to; int next; int dist; }bian[1000010]={{0,0,0}}; int Size[1000010]={0}; long long ans=0; void Addbian(int p,int q,int r,int k) { bian[k].to=q; bian[k].dist=r; bian[k].next=First[p]; First[p]=k; return; } void Add(int t,int c) { int cnt=New[t-1];New[t]=++pp;pot[New[t]].lenth=pot[New[t-1]].lenth+1; for(;cnt!=0 && pot[cnt].ch[c]==0;cnt=pot[cnt].fail) pot[cnt].ch[c]=New[t]; if(cnt==0) pot[New[t]].fail=1; else { int q=pot[cnt].ch[c]; if(pot[cnt].lenth+1==pot[q].lenth) pot[New[t]].fail=q; else { pp++;pot[pp]=pot[q];pot[pp].lenth=pot[cnt].lenth+1; pot[q].fail=pot[New[t]].fail=pp; for(;cnt!=0 && pot[cnt].ch[c]==q;cnt=pot[cnt].fail) pot[cnt].ch[c]=pp; } } return; } void dfs(int cnt,int depth) { for(int i=First[cnt];i!=0;i=bian[i].next) { int u=bian[i].to; dfs(u,depth+bian[i].dist); ans-=(long long)depth*Size[u]*Size[cnt]*2; Size[cnt]+=Size[u]; } if(New[pot[cnt].lenth]==cnt) { ans-=(long long)depth*Size[cnt]*2; Size[cnt]++; } return; } int main() { scanf("%s",str+1); N=strlen(str+1); New[0]=++pp; for(int i=1;i<=N;i++) { Add(i,str[N-i+1]-'a'); ans+=(long long)i*(N-1); } for(int i=2;i<=pp;i++) Addbian(pot[i].fail,i,pot[i].lenth-pot[pot[i].fail].lenth,i-1); dfs(1,0); cout<<ans<<endl; return 0; }
相关文章推荐
- JMeter性能测试基础 (3) - 使用参数文件做搜索引擎性能对比
- JQuery实现鼠标经过事件
- CF #244 (Div. 2)D
- BZOJ 2257: [Jsoi2009]瓶子和燃料 裴蜀定理
- as3.0----flash复制功能在网页上面的小小应用
- 在Mathematica中定义矩阵的半张量积运算
- 百度之星的第二个问题
- 程序员能看懂的笑话
- armv7架构下lubuntu系统apt-get安装ffmpeg方法
- Android之AutoCompleteTextView自动匹配(笔记)
- Android代码优化——使用Android lint工具
- javascript canvas fps 帧速率计算
- 2012中国国家集训队命题答辩tree(伍一鸣)
- cocos2d-x 内存管理浅析
- 检查软件下载是否完整 MD5 工具使用 ----- md5sum
- 软件安全学习笔记(4):磁盘的物理逻辑结构
- android Shader类简介_渲染图像示例
- 加载模块时出现unknown partition table 的原因
- 统计二进制中1的个数
- VFL子视图居中