标签:blank code max char s targe 统计 str 长度 sam
原文链接http://www.cnblogs.com/zhouzhendong/p/9026184.html
求一个串中,所有本质不同子串的出现次数的平方和。
$|s|\leq 10^5$
首先,这一题用$SAM$做就是模板题,比较简单。
但是,本着练一练$SA$的心态,我开始了$SA+单调栈$的苦海。
真毒瘤。
这里讲一讲$SA$的做法,也是经典的做法。
$SA$闭着眼睛先写了再说。
首先,我们考虑出现次数大于$1$次的子串。
考虑按照$SA$数组的顺序来进行处理,这样得到的后缀的字典序不断变大。
如果要统计一个串与前一个串的$LCP$出现了多少次,该如何统计?
显然是往前和往后都找到第一个$LCP$比当前小的停止并统计。
于是我们用单调栈来维护一个$height$升序的序列。具体的统计方法这里不多赘述,可以直接查阅代码。比较明了。
单调栈要注意处理当前$LCP$和栈顶$LCP$长度值相同的情况。
考虑只出现一次的串个数。对于第$i$大的后缀(即$SA[i]$),之前统计到的是$SA[i]$与$SA[i-1]$、$SA[i]$与$SA[i+1]$的$LCP$的$\max$。于是没用统计到的就是剩下的。于是当前后缀出现依次的串对答案的贡献就是$len-\max$。
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int N=100005; int T,n,m,SA[N],rank[N],height[N],tmp[N],tax[N]; char s[N]; int st[N],top,pos[N]; void Sort(int n,int m){ for (int i=0;i<=m;i++) tax[i]=0; for (int i=1;i<=n;i++) tax[rank[i]]++; for (int i=1;i<=m;i++) tax[i]+=tax[i-1]; for (int i=n;i>=1;i--) SA[tax[rank[tmp[i]]]--]=tmp[i]; } bool cmp(int rk[],int x,int y,int w){ return rk[x]==rk[y]&&rk[x+w]==rk[y+w]; } void Suffix_Array(char s[],int n){ memset(SA,0,sizeof SA); memset(tmp,0,sizeof tmp); memset(rank,0,sizeof rank); memset(height,0,sizeof height); for (int i=1;i<=n;i++) rank[i]=s[i],tmp[i]=i; m=127; Sort(n,m); for (int w=1,p=0;p<n;w<<=1,m=p){ p=0; for (int i=n-w+1;i<=n;i++) tmp[++p]=i; for (int i=1;i<=n;i++) if (SA[i]>w) tmp[++p]=SA[i]-w; Sort(n,m); swap(rank,tmp); rank[SA[1]]=p=1; for (int i=2;i<=n;i++) rank[SA[i]]=cmp(tmp,SA[i],SA[i-1],w)?p:++p; } for (int i=1,j,k=0;i<=n;height[rank[i++]]=k) for (k=max(k-1,0),j=SA[rank[i]-1];s[i+k]==s[j+k];k++); } int main(){ scanf("%d",&T); while (T--){ scanf("%s",s+1); n=strlen(s+1); Suffix_Array(s,n); LL ans=0; top=0; memset(st,0,sizeof st); memset(pos,0,sizeof pos); SA[n+1]=height[0]=0; for (int i=2;i<=n+1;i++){ int nowpos=i,len=height[i]; while (top>0&&st[top]>len){ LL v1=st[top]-max(st[top-1],len); LL v2=i-pos[top]+1; ans+=v1*v2*v2; nowpos=pos[top--]; } while (top>0&&st[top]==len) nowpos=pos[top--]; st[++top]=len; pos[top]=nowpos; } for (int i=1;i<=n;i++) ans+=n-i+1-max(height[rank[i]],height[rank[i]+1]); printf("%I64d\n",ans); } return 0; }
Codeforces 802I Fake News (hard) (SA+单调栈) 或 SAM
标签:blank code max char s targe 统计 str 长度 sam
原文地址:https://www.cnblogs.com/zhouzhendong/p/9026184.html