[bzoj 4566][Haoi 2016]找相同字符
阿新 • • 發佈:2019-01-26
int desc mem ace face -i blog can its
傳送門
Description
給定兩個字符串,求出在兩個字符串中各取出一個子串使得這兩個子串相同的方案數。兩個方案不同當且僅當這兩個子串中有一個位置不同。
Solution
考慮用SAM,采用較為輕松的姿勢
首先中加個特殊符號,把連個字符串接在一起
SAM的每個節點都存下了一些子串,我們分別記下它在\(s_1\)和\(s_2\)中出現的次數
那麽每個狀態它給答案的貢獻是
\[ (step[i]-step[fa[i]]) × siz_{s_1}[i]×siz_{s_2}[i] \]
Code?
//2019.1.25 23:00~23:18 #include<bits/stdc++.h> #define ll long long #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) #define MN 200005 char s[MN]; class SAM { #define MX 800005 private: int last,cnt,fa[MX],v[MX],rk[MX],val[MX][2],c[MX][27],step[MX];ll ans; public: SAM(int _=1):last(_),cnt(_){} inline void Insert(int x,bool pos) { int p=last,np=++cnt;step[np]=step[p]+1;val[np][pos]=1; for(;p&&!c[p][x];p=fa[p]) c[p][x]=np; if(!p) fa[np]=1; else { int q=c[p][x]; if(step[q]==step[p]+1) fa[np]=q; else { int nq=++cnt; fa[nq]=fa[q];fa[np]=fa[q]=nq; memcpy(c[nq],c[q],sizeof c[nq]); step[nq]=step[p]+1; for(;c[p][x]==q;p=fa[p]) c[p][x]=nq; } } last=np; } inline void Query() { register int i; for(i=1;i<=cnt;++i) ++v[step[i]]; for(i=1;i<=step[last];++i) v[i]+=v[i-1]; for(i=1;i<=cnt;++i) rk[v[step[i]]--]=i; for(i=cnt;i;--i) { val[fa[rk[i]]][0]+=val[rk[i]][0]; val[fa[rk[i]]][1]+=val[rk[i]][1]; ans+=1ll*val[rk[i]][0]*val[rk[i]][1]*(step[rk[i]]-step[fa[rk[i]]]); } val[1][0]=val[1][1]=0; printf("%lld\n",ans); } }pac; int main() { scanf("%s",s+1); register int n=strlen(s+1),i; for(i=1;i<=n;++i) pac.Insert(s[i]-'a',0); pac.Insert(26,0); scanf("%s",s+1);n=strlen(s+1); for(i=1;i<=n;++i) pac.Insert(s[i]-'a',1); pac.Query(); return 0; }
Blog來自PaperCloud,未經允許,請勿轉載,TKS!
[bzoj 4566][Haoi 2016]找相同字符