后缀自动机小练总结(Spoj1811&&Hdu4416&&CodeForces235C)
来源:互联网 发布:js获取本地file对象 编辑:程序博客网 时间:2024/05/20 02:21
今天总体复习一下字符串……
后缀自动机是重点,以前就没学懂……
SPOJ1811LCS:
一个串建立自动机,另一个每个节点都在上面跑,记录当前可以匹配的长度更新ans即可
#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const int maxn=3000000+10;int ans=0; char s[maxn];struct Suffix_Automation{int son[maxn][26],l[maxn],tmp;int last,tot,root,fa[maxn],lastp;void init(){tot=0; last=root=++tot; tmp=0; lastp=root;}void add(int w){int p=last,np=++tot; last=np; l[np]=l[p]+1;while (p&&!son[p][w]) son[p][w]=np,p=fa[p];if (!p){fa[np]=root;}else{int q=son[p][w];if (l[q]==l[p]+1) fa[np]=q;else{int nq=++tot; l[nq]=l[p]+1; fa[nq]=fa[q];for (int i=0;i<26;++i) son[nq][i]=son[q][i];fa[np]=fa[q]=nq;while (p&&son[p][w]==q) son[p][w]=nq,p=fa[p];}}}void solve_LCS(int w){if (son[lastp][w]) tmp++,ans=max(tmp,ans),lastp=son[lastp][w];else{while (lastp&&!son[lastp][w]) lastp=fa[lastp];if (!lastp) lastp=root,tmp=0;else tmp=l[lastp]+1,ans=max(ans,tmp),lastp=son[lastp][w];}}}SAM;int main(){SAM.init();scanf("%s",s+1); int n=strlen(s+1);for (int i=1;i<=n;++i)SAM.add(s[i]-'a');scanf("%s",s+1); n=strlen(s+1);for (int i=1;i<=n;++i)SAM.solve_LCS(s[i]-'a');printf("%d",ans);}
Hdu4416
问A串中有多少个字串不是B的字串
做法基本同上一题,也是先建立一个自动机,另外一些在上面跑,在自动机上每个节点记录dep表示它可以与B中的串的最大匹配长度
然后一遍基数排序搞出一个具有拓扑性质的节点序列用儿子的dep更新fa的dep,那么l[x]-dep[x]即为当前节点的贡献
注意dep[x]==0时特判
#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>#include<algorithm>#define LL long longusing namespace std;const int maxn=220000;int n; LL ans=0;char s[maxn],t[maxn];struct Suffix_Automation{int son[maxn][26],l[maxn];int last,root,tot,fa[maxn];int lastp,tmp; int dep[maxn];int c[maxn],rk[maxn];void init(){tot=0; last=root=++tot;memset(l,0,sizeof(l));memset(fa,0,sizeof(fa));memset(son,0,sizeof(son));memset(dep,0,sizeof(dep));memset(c,0,sizeof(c));}void add(int w){int p=last,np=++tot; last=np; l[np]=l[p]+1;while (p&&!son[p][w]) son[p][w]=np,p=fa[p];if (!p){fa[np]=root;}else{int q=son[p][w];if (l[q]==l[p]+1) fa[np]=q;else{int nq=++tot; l[nq]=l[p]+1; fa[nq]=fa[q];for (int i=0;i<26;++i) son[nq][i]=son[q][i];fa[np]=fa[q]=nq;while (p&&son[p][w]==q) son[p][w]=nq,p=fa[p];}}}void solvedep(int w){if (son[lastp][w]) lastp=son[lastp][w],tmp++,dep[lastp]=max(dep[lastp],tmp);else{while (lastp&&!son[lastp][w]) lastp=fa[lastp];if (!lastp) lastp=root,tmp=0;else tmp=l[lastp]+1,lastp=son[lastp][w],dep[lastp]=max(dep[lastp],tmp);}}void getans(int x){int mxl=0;for (int i=1;i<=tot;++i) c[l[i]]++,mxl=max(mxl,l[i]);for (int i=1;i<=mxl;++i) c[i]+=c[i-1];for (int i=1;i<=tot;++i) rk[c[l[i]]--]=i;for (int i=tot;i>=1;--i){int x=rk[i]; dep[fa[x]]=max(dep[fa[x]],dep[x]); if (dep[x]&&dep[x]<l[x]) ans+=l[x]-dep[x]; else if (!dep[x]) ans+=l[x]-l[fa[x]];}}}SAM;void solve(int Case){scanf("%d",&n);SAM.init(); scanf("%s",s+1);int L=strlen(s+1); for (int i=1;i<=L;++i) SAM.add(s[i]-'a');for (int i=1;i<=n;++i){scanf("%s",t+1); SAM.tmp=0; int len=strlen(t+1); SAM.lastp=SAM.root; for (int j=1;j<=len;++j) SAM.solvedep(t[j]-'a');}ans=0; SAM.getans(SAM.root);printf("Case %d: %lld\n",Case,ans);}int main(){int T; scanf("%d",&T);for (int i=1;i<=T;++i) solve(i);}
Codeforces235C
给题解打个广告QAQ:题解
#include<cstdio>#include<vector>#include<cstdlib>#include<cstring>#include<iostream>#include<algorithm>#define LL long longusing namespace std;const int maxn=2100000+10;int n,lenS; LL ret;vector<int>ans;char s[maxn],t[maxn];struct Suffix_Automation{int son[maxn][26],l[maxn],lastp;int tot,last,root,fa[maxn],tmp;int c[maxn],rk[maxn],num[maxn];bool flag[maxn];void init(){tot=0; last=root=++tot; memset(flag,0,sizeof(flag));}void add(int w){int p=last,np=++tot; last=np; l[np]=l[p]+1; num[np]=1;while (p&&!son[p][w]) son[p][w]=np,p=fa[p];if (!p){fa[np]=root;}else{int q=son[p][w];if (l[q]==l[p]+1) fa[np]=q;else{int nq=++tot; l[nq]=l[p]+1; fa[nq]=fa[q];for (int i=0;i<26;++i) son[nq][i]=son[q][i];fa[np]=fa[q]=nq;while (p&&son[p][w]==q) son[p][w]=nq,p=fa[p];}}}void solvepre(int w){if (son[lastp][w]) lastp=son[lastp][w],tmp++;else{while (lastp&&!son[lastp][w]) lastp=fa[lastp];if (!lastp) lastp=root,tmp=0;else tmp=l[lastp]+1,lastp=son[lastp][w];}while (l[fa[lastp]]>=lenS){lastp=fa[lastp];tmp=l[lastp];}if (!flag[lastp]&&tmp>=lenS){ans.push_back(lastp);flag[lastp]=1;}}void getnum(){int mxl=0;for (int i=1;i<=tot;++i) c[l[i]]++,mxl=max(mxl,l[i]);for (int i=1;i<=mxl;++i) c[i]+=c[i-1];for (int i=tot;i;--i) rk[c[l[i]]--]=i;for (int i=tot;i;--i){int x=rk[i];num[fa[x]]+=num[x];}}void getans(){ret=0;for (int i=0;i<ans.size();++i){ret+=num[ans[i]];flag[ans[i]]=0;}ans.clear(); cout<<ret<<endl;}}SAM;int main(){SAM.init();scanf("%s",s+1); lenS=strlen(s+1);for (int i=1;i<=lenS;++i) SAM.add(s[i]-'a');SAM.getnum(); scanf("%d",&n);for (int i=1;i<=n;++i){scanf("%s",t+1); int len=strlen(t+1); lenS=len;for (int i=len+1;i<=len*2-1;++i) t[i]=t[i-len];len=len*2-1; SAM.lastp=SAM.root; SAM.tmp=0; for (int j=1;j<=len;++j) SAM.solvepre(t[j]-'a');SAM.getans();} }
2 0
- 后缀自动机小练总结(Spoj1811&&Hdu4416&&CodeForces235C)
- HDU4416(后缀自动机)
- SPOJ1811 [后缀自动机]
- SPOJ1811 后缀自动机入门
- hdu4416——后缀自动机
- hdu4416[多串后缀自动机]
- 【后缀自动机】SPOJLCS SPOJNSUBSTR SPOJLCS2 HDU4416
- 【后缀自动机】SPOJLCS SPOJNSUBSTR SPOJLCS2 HDU4416
- SPOJ1811 Longest Common Substring后缀自动机
- [SPOJ1811]Longest Common Substring-后缀自动机
- 后缀自动机(不同子串的个数)hdu4416
- SPOJ1811最长公共子串问题(后缀自动机)
- spoj1811 Longest Common Substring(LCS),后缀自动机
- 后缀自动机(最长公共子串、模板)spoj1811
- [SPOJ1811]LCS - Longest Common Substring(后缀自动机)
- 后缀自动机学习总结
- 后缀自动机总结
- 后缀自动机总结
- 屏幕适配
- jquerymobile-6 自适应header、footer和全屏视图
- 【OpenGL】Dota2 Shader分析(1)
- C开发、Android专业人员
- C++单向链表反转
- 后缀自动机小练总结(Spoj1811&&Hdu4416&&CodeForces235C)
- 蓝桥杯 基础练习 闰年判断
- mysql字段类型详解
- 关于free如何知道要释放内存空间的长度问题
- VC10中的C++0x特性 Part 2 :右值引用
- 文本视图 UITextView
- Android 获取字符串高度与宽度
- 第十八讲--检查点队列(checkpoint queue)
- 关于自定义tabbar修改字体颜色及图标选中颜色等方法的总结