P4248 [AHOI2013]差異 解題報告
阿新 • • 發佈:2018-12-15
P4248 [AHOI2013]差異
題目描述
給定一個長度為 \(n\) 的字串 \(S\),令 \(T_i\) 表示它從第 \(i\) 個字元開始的字尾。求
\[\displaystyle \sum_{1\leqslant i<j\leqslant n}\text{len}(T_i)+\text{len}(T_j)-2\times\text{lcp}(T_i,T_j)\]
其中,\(\text{len}(a)\)表示字串 \(a\) 的長度,\(\text{lcp}(a,b)\) 表示字串 \(a\) 和字串 \(b\) 的最長公共字首。
輸入輸出格式
輸入格式:
一行,一個字串 \(S\)
輸出格式:
一行,一個整數,表示所求值。
說明
對於 \(100\%\) 的資料,保證 \(2\leqslant n\leqslant 500000\),且均為小寫字母。
思路:先用SA求出height陣列,然後從最小的開始刪並維護聯通性,發現用可以用單調棧處理這個過程。
我人太傻一開始求錯了演算法迷了好久...
Code:
#include <cstdio> #include <cstring> #include <algorithm> #define ll long long const int N=5e5+10; int sa[N],Rank[N],tax[N],sec[N],height[N],sta[N],L[N],R[N],tot,n,m; char s[N]; void Rsort() { for(int i=1;i<=m;i++) tax[i]=0; for(int i=1;i<=n;i++) ++tax[Rank[i]]; for(int i=2;i<=m;i++) tax[i]+=tax[i-1]; for(int i=n;i;i--) sa[tax[Rank[sec[i]]]--]=sec[i]; } bool cmp(int x,int y,int l){return sec[x]==sec[y]&&sec[x+l]==sec[y+l];} void SuffixSort() { scanf("%s",s+1);n=strlen(s+1); for(int i=1;i<=n;i++) Rank[i]=s[i]+1-'a',sec[i]=i; m=26;Rsort(); for(int p=0,w=1;p<n;w<<=1,m=p) { p=0;for(int i=n-w+1;i<=n;i++) sec[++p]=i; for(int i=1;i<=n;i++) if(sa[i]>w) sec[++p]=sa[i]-w; Rsort();std::swap(Rank,sec); Rank[sa[1]]=p=1; for(int i=2;i<=n;i++) Rank[sa[i]]=cmp(sa[i],sa[i-1],w)?p:++p; } for(int p=0,i=1;i<=n;height[Rank[i++]-1]=p) for(p=p?p-1:p;s[i+p]==s[sa[Rank[i]-1]+p];++p); } int main() { SuffixSort(); for(int i=1;i<n;i++) { while(tot&&height[sta[tot]]>=height[i]) --tot; L[i]=sta[tot]+1; sta[++tot]=i; } sta[tot=0]=n; for(int i=n-1;i;i--) { while(tot&&height[sta[tot]]>height[i]) --tot; R[i]=sta[tot]-1; sta[++tot]=i; } ll ans=1ll*(n+1)*(n-1)*n/2; for(int i=1;i<n;i++) ans-=2ll*(R[i]-i+1)*(i-L[i]+1)*height[i]; printf("%lld\n",ans); return 0; }
2018.12.15