hdu5343 后缀自动机+dp
生活随笔
收集整理的這篇文章主要介紹了
hdu5343 后缀自动机+dp
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
給定兩個串,分別截取字串X和Y,連接組成X+Y,求不同的X+Y的方案數(shù)。
對于X+Y,如果重復(fù)的部分其實就是從同一個X+Y的某個地方斷開弄成不同的X和Y,那么只要使得X和X+Y匹配得最長就行了。
因此,對兩個字符串分別建立后綴自動機(jī)A和B,在A中找字串X,當(dāng)X的末尾不能接某個字符c時,在B中找以c為開頭的所有字串。
注意字串的是n^2個,所以不管怎樣都不能以暴力遍歷自動機(jī)的方式來統(tǒng)計,而由于SAM是DAG,所以實際上是在兩個DAG上進(jìn)行dp。
?
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) memset(a,0,sizeof(a))using namespace std;typedef unsigned long long ll; const int maxn=1000100; const int INF=1e9+10;char s[maxn],t[maxn]; ll dp1[maxn],dp2[maxn];struct SAM {int ch[maxn][26];int pre[maxn],step[maxn];int last,tot;void init(){last=tot=0;memset(ch[0],-1,sizeof(ch[0]));pre[0]=-1;step[0]=0;}void add(int c){c-='a';int p=last,np=++tot;step[np]=step[p]+1;memset(ch[np],-1,sizeof(ch[np]));while(~p&&ch[p][c]==-1) ch[p][c]=np,p=pre[p];if(p==-1) pre[np]=0;else{int q=ch[p][c];if(step[q]!=step[p]+1){int nq=++tot;step[nq]=step[p]+1;memcpy(ch[nq],ch[q],sizeof(ch[q]));pre[nq]=pre[q];pre[q]=pre[np]=nq;while(~p&&ch[p][c]==q) ch[p][c]=nq,p=pre[p];}else pre[np]=q;}last=np;} };SAM A,B;ll dfs2(int u) {if(u==-1) return 0;ll &res=dp2[u];if(~res) return res;res=1;REP(c,0,25) res+=dfs2(B.ch[u][c]);return res; }ll dfs1(int u) {ll &res=dp1[u];if(~res) return res;res=1;REP(c,0,25){if(~A.ch[u][c]) res+=dfs1(A.ch[u][c]);else res+=dfs2(B.ch[0][c]);}return res; }void solve() {A.init();B.init();int ls=strlen(s),lt=strlen(t);REP(i,0,ls-1) A.add(s[i]);REP(i,0,lt-1) B.add(t[i]);memset(dp1,-1,sizeof(dp1));memset(dp2,-1,sizeof(dp2));printf("%I64u\n",dfs1(0)); }int main() {freopen("in.txt","r",stdin);int T;cin>>T;while(T--){scanf("%s%s",s,t);solve();}return 0; } View Code?
轉(zhuǎn)載于:https://www.cnblogs.com/--560/p/5457826.html
總結(jié)
以上是生活随笔為你收集整理的hdu5343 后缀自动机+dp的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android之自定义View的实现
- 下一篇: 关于function和Object的认识