【BZOJ3238】【AHOI2013】差异
sam好,好写好调好ac!
原题:
图片题面好评
2<=N<=500000
在syq大神的指点下终于理解一道后缀自动姬了quq
(其实是因为这道题的dp主要是在后缀树(就是拓扑序)上搞树形dp……
恩sam有个好玩的东西呢就是搞出后缀自动姬后根据max搞一个类似与后缀数组中countrank的东西
这个就是自动姬的拓扑序,同时也是parent树的不知道什么序,反正如果倒叙遍历这个序列的话x一定会比father[x]先访问到就对了
然后就可以直接用countrank搞树形dp辣
每个树点对答案的贡献就是(max[x]-max[father[x]])*C_{|right[x]|}^{2}
写到这里我突然发现这个组合数不太理解啊,如果两个节点在同一个子节点的子树中怎么办……
一定是还有什么性质我没考虑到
syq回寝吃泡面了,只能回去问syq了quq
啊,syq吃完泡面后讲明白了quq
就像下面酱紫一个图:
在这个后缀树中,现在计算2节点对于答案的贡献
我本来的想法是如果直接用2的深度乘C_{子树大小}^{2}岂不是会出现两个节点在同一子节点的子树中然后重复计算的情况?
但是实际上在计算贡献的时候是用(max[x]-max[father[x]])乘组合数的,这个表示的是2和1之间的连边,而不是2的深度
2和1对答案的贡献显然就乘C_{子树大小}^{2}
这样就解决了Σlcp(i,j)*2的问题,至于前面那些东西,最后结果是(n+1)*(n-1)*n/2,请同学们自行推到 _(:3 」∠)_
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 using namespace std; 7 #define ll long long 8 int rd(){int z=0,mk=1; char ch=getchar(); 9 while(ch<'0'||ch>'9'){if(ch=='-')mk=-1; ch=getchar();} 10 while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0'; ch=getchar();} 11 return z*mk; 12 } 13 char s[510000]; int n; 14 int nxt[1100000][26],fa[1100000],mx[1100000],sz[1100000],sm[1100000]; 15 int lst=1,tt=1; 16 int cnt[1100000],cntrk[1100000]; 17 void ist(int x){ 18 int p=lst,np=lst=++tt; 19 mx[np]=mx[p]+1; sz[np]=sm[np]=1; 20 while(!nxt[p][x] && p) nxt[p][x]=np,p=fa[p]; 21 if(!p) fa[np]=1; 22 else{ 23 int q=nxt[p][x]; 24 if(mx[p]+1==mx[q]) fa[np]=q; 25 else{ 26 int nq=++tt; mx[nq]=mx[p]+1; 27 memcpy(nxt[nq],nxt[q],sizeof(nxt[q])); 28 fa[nq]=fa[q]; fa[q]=fa[np]=nq; 29 while(nxt[p][x]==q) nxt[p][x]=nq,p=fa[p]; 30 } 31 } 32 } 33 void gtcntrk(){ 34 for(int i=1;i<=tt;++i) ++cnt[mx[i]]; 35 for(int i=1;i<=n;++i) cnt[i]+=cnt[i-1]; 36 for(int i=tt;i;--i) cntrk[cnt[mx[i]]--]=i; 37 } 38 ll play(){ 39 ll bwl=0; 40 for(int i=tt;i;--i){ 41 sz[fa[cntrk[i]]]+=sz[cntrk[i]]; 42 /*bwl+=(ll)sm[fa[cntrk[i]]]*sz[cntrk[i]]*mx[fa[cntrk[i]]]; 43 sm[fa[cntrk[i]]]+=sz[cntrk[i]];*/ 44 bwl+=(ll)(mx[cntrk[i]]-mx[fa[cntrk[i]]])*sz[cntrk[i]]*(sz[cntrk[i]]-1); 45 } 46 return bwl; 47 } 48 int main(){//freopen("ddd.in","r",stdin); 49 scanf("%s",s+1); n=strlen(s+1); 50 for(int i=1;i<=n;++i) ist(s[i]-'a'); 51 gtcntrk(); 52 cout<<(ll)(n+1)*n/2*(n-1)-play()<<endl; 53 return 0; 54 }