spoj 8222 Substrings (后缀自动机+dp)
2015-03-09 23:26
260 查看
题意:
给出一个串,定义这样的F(x){ 表示在长度为x的串中出现次数最多的串的长度 },求出F(i) 1<=i<=len
题解:
刚接触后缀自动机不会很懂,多亏大牛 在做这题前最好看下陈立杰的写的关于后缀数组的论文。论文中提到right(s),表示从s状态出发能到达的所有串的最后一个点的一个集合。len[i]表示在建后缀机的过程中某个过程对应的后缀长度,注意最后不一定会是整个串的后缀,但是可以将len[i]作为一个子串的长度来用。那么要得到s状态能到达的集合right,求出这个集合元素个数,这个个数就是s对应串出现的次数。我们根据right来根性max(s),采用dp来做,从大到小进行dp,这样就保证没有后效性,而且由于长度长的子串出现了某个次数,对应的更短子串也会出现同样次数,记得陈立杰论文提到right之间要么是包含关系要么不想交。由于spoj很慢,我们选择用桶排序(基数排序)。发现其实只要有状态的地方就可以dp,尤其是自动机的dp,越发感觉妙不可言。
给出一个串,定义这样的F(x){ 表示在长度为x的串中出现次数最多的串的长度 },求出F(i) 1<=i<=len
题解:
刚接触后缀自动机不会很懂,多亏大牛 在做这题前最好看下陈立杰的写的关于后缀数组的论文。论文中提到right(s),表示从s状态出发能到达的所有串的最后一个点的一个集合。len[i]表示在建后缀机的过程中某个过程对应的后缀长度,注意最后不一定会是整个串的后缀,但是可以将len[i]作为一个子串的长度来用。那么要得到s状态能到达的集合right,求出这个集合元素个数,这个个数就是s对应串出现的次数。我们根据right来根性max(s),采用dp来做,从大到小进行dp,这样就保证没有后效性,而且由于长度长的子串出现了某个次数,对应的更短子串也会出现同样次数,记得陈立杰论文提到right之间要么是包含关系要么不想交。由于spoj很慢,我们选择用桶排序(基数排序)。发现其实只要有状态的地方就可以dp,尤其是自动机的dp,越发感觉妙不可言。
#include<iostream> #include<math.h> #include<stdio.h> #include<algorithm> #include<string.h> #include<vector> #include<queue> #include<map> #include<set> using namespace std; #define B(x) (1<<(x)) typedef long long ll; const int oo=0x3f3f3f3f; const ll OO=1LL<<61; const int MOD=10007; const int maxn=250005; const int SIZE=maxn<<2; const int type=26; int next[SIZE][type],fa[SIZE],len[SIZE]; int tol,last; int g[SIZE],dp[maxn],cnt[SIZE],pos[SIZE]; char str[maxn]; int newNode(int x){ len[tol]=x; fa[tol]=-1; for(int i=0;i<type;i++){ next[tol][i]=-1; } return tol++; } void Init(){ tol=0; last=newNode(0); } void add(int k){ int now=last; int end=newNode(len[now]+1); while(now!=-1&&next[now][k]==-1){ next[now][k]=end; now=fa[now]; } if(now==-1) fa[end]=0; else{ int nxt=next[now][k]; if(len[now]+1==len[nxt]) fa[end]=nxt; else{ int cnxt=newNode(len[now]+1); for(int i=0;i<type;i++)next[cnxt][i]=next[nxt][i]; fa[cnxt]=fa[nxt]; fa[nxt]=fa[end]=cnxt; while(now!=-1&&next[now][k]==nxt){ next[now][k]=cnxt; now=fa[now]; } } } last=end; } void Insert(char buff[],int L){ for(int i=0;i<L;i++) add(buff[i]-'a'); } int main(){ scanf("%s",str); int L=strlen(str); Init(); Insert(str,L); for(int i=0;i<tol;i++)cnt[i]=0; for(int i=0;i<tol;i++)cnt[len[i]]++; for(int i=1;i<tol;i++)cnt[i]+=cnt[i-1]; for(int i=tol-1;i>=0;i--)pos[--cnt[len[i]]]=i; for(int i=0;i<tol;i++)g[i]=0; for(int i=0;i<=L;i++)dp[i]=0; int p=0; for(int i=0;i<L;i++)g[p=next[p][str[i]-'a']]++; for(int i=tol-1;i>=0;i--){ p=pos[i]; dp[len[p]]=max(dp[len[p]],g[p]); g[fa[p]]+=g[p]; } for(int i=L-1;i>=1;i--)dp[i]=max(dp[i],dp[i+1]); for(int i=1;i<=L;i++)printf("%d\n",dp[i]); return 0; }
相关文章推荐
- spoj 8222 Substrings(后缀自动机+DP)
- spoj 8222 substrings 【后缀自动机】
- SPOJ 题目 8222 NSUBSTR - Substrings(后缀自动机+DP求子串出现最大次数)
- ●SPOJ 8222 NSUBSTR–Substrings(后缀自动机)
- SPOJ 8222. Substrings(后缀自动机模板)
- SPOJ 8222 Substrings(后缀自动机)
- spoj 8222 Substrings(后缀自动机)
- SPOJ 8222 Substrings 后缀自动机
- SPOJ 8222 NSUBSTR - Substrings (后缀自动机)
- Sphere 8222 Substrings【后缀自动机+dp】
- spoj 8222 Substrings (后缀自动机)
- spoj 8222 Substrings (后缀自动机)
- 【SPOJ】8222. Substrings(后缀自动机)
- SPOJ 8222 Substrings 后缀自动机入门
- SPOJ 8222 Substrings(后缀自动机)
- SPOJ NSUBSTR Substrings ——后缀自动机
- SPOJ 8222 NSUBSTR 后缀自动机
- SPOJ NSUBSTR(Substrings-后缀自动机统计串出现次数-Right集合&Parent树の暴走)
- 【SPOJ】Substrings(后缀自动机)
- 【SPOJ】Substrings(后缀自动机)