P4248-[AHOI2013]差异【SAM or SA】
正題
題目鏈接:https://www.luogu.com.cn/problem/P4248
題目大意
TiT_iTi?表示后綴i~ni\sim ni~n
一個字符串求
∑i=1n∑j=inlen(Ti)+len(Tj)?2?lcp(Ti,Tj)\sum_{i=1}^n\sum_{j=i}^nlen(T_i)+len(T_j)-2*lcp(T_i,T_j)i=1∑n?j=i∑n?len(Ti?)+len(Tj?)?2?lcp(Ti?,Tj?)
解題思路
有兩種做法,這里標程用的是SAMSAMSAM
SAMSAMSAM做法
這個式子和樹上路徑長度很像,順著這個思路,我們可以想到SAMSAMSAM上的ParentParentParent樹。
兩個后綴的lcplcplcp就是ParentParentParent樹上的LCALCALCA的節點代表的字符串,我們讓邊長為lenx?lenfailxlen_x-len_{fail_x}lenx??lenfailx??,然后答案就變為了樹上的每條路徑長度和。
那一條邊的貢獻就是(num?sizx)?sizx?len(num-siz_x)*siz_x*len(num?sizx?)?sizx??len‘
統計即可,時間復雜度O(n)O(n)O(n)
SASASA做法
我們先計算定值∑i=1n∑j=inlen(Ti)+len(Tj)\sum_{i=1}^n\sum_{j=i}^nlen(T_i)+len(T_j)∑i=1n?∑j=in?len(Ti?)+len(Tj?)
這里的定值就是n?(n?1)?(n+1)2\frac{n*(n-1)*(n+1)}{2}2n?(n?1)?(n+1)?
然后我們考慮如何計算LCPLCPLCP的和
heighti=LCP(i,i?1)height_i=LCP(i,i-1)heighti?=LCP(i,i?1)
我們有LCP(i,j)=min{heightk}(i<k≤j)LCP(i,j)=min\{height_k\}(i<k\leq j)LCP(i,j)=min{heightk?}(i<k≤j)
所以這里的答案就變為了∑i=2n∑j=inmin{heightk}(i≤k≤j)\sum_{i=2}^{n}\sum_{j=i}^nmin\{height_k\}(i\leq k\leq j)i=2∑n?j=i∑n?min{heightk?}(i≤k≤j)
我們每個heightiheight_iheighti?的貢獻分開統計即可
codecodecode
#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll N=2e6+10; struct node{ll to,next,w; }a[N]; ll n,tot,ls[N],ans,num,siz[N]; ll next[N][26],len[N],fail[N],cnt; char s[N]; void New_Point(ll x,ll v){next[x][v]=++cnt;len[cnt]=len[x]+1; } void addl(ll x,ll y,ll w){a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;a[tot].w=w; } void Make_SAM(){ll now;now=cnt=1;for(ll i=1;i<=n;i++){ll val=s[i]-'a';New_Point(now,val);ll x=now,y;now=cnt;for(y=fail[x];y;y=fail[y])if(!next[y][val])next[y][val]=now;else{if(len[y]+1==len[next[y][val]])fail[now]=next[y][val];else{ll z=next[y][val];New_Point(y,val);fail[cnt]=fail[z];fail[z]=fail[now]=cnt;for(ll i=0;i<26;i++)next[cnt][i]=next[z][i];for(ll j=y;j;j=fail[j])if(next[j][val]==z)next[j][val]=cnt;}break;}siz[now]=1;if(!y) fail[now]=1;}for(ll i=2;i<=cnt;i++){num+=siz[i];addl(fail[i],i,len[i]-len[fail[i]]);} } void dfs(ll x){for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;dfs(y);ans+=siz[y]*(num-siz[y])*a[i].w;siz[x]+=siz[y];} } int main() {scanf("%s",s+1);n=strlen(s+1);Make_SAM();dfs(1);printf("%lld",ans); }總結
以上是生活随笔為你收集整理的P4248-[AHOI2013]差异【SAM or SA】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: P5496-[模板]回文自动机【PAM】
- 下一篇: 笔记本电脑开机后屏幕不亮怎么办笔记本的电