日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

P4248-[AHOI2013]差异【SAM or SA】

發布時間:2023/12/3 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 P4248-[AHOI2013]差异【SAM or SA】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

正題

題目鏈接:https://www.luogu.com.cn/problem/P4248


題目大意

TiT_iTi?表示后綴i~ni\sim nin
一個字符串求
∑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=1n?j=in?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<kj)
所以這里的答案就變為了∑i=2n∑j=inmin{heightk}(i≤k≤j)\sum_{i=2}^{n}\sum_{j=i}^nmin\{height_k\}(i\leq k\leq j)i=2n?j=in?min{heightk?}(ikj)
我們每個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】的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。