poj 2752 Seek the Name, Seek the Fame
Seek the Name, Seek the Fame
题目大意:输入一串全为小写字母的字符串,字符串长度小于400000,输出所有满足前缀和后缀相等的字符的长度,这个”组合条件“我会在样例中说明。
第一组样例解释:
样例一:ababcababababcabab 2:ababcababababcabab 4:ababcabababcabab 9:ababcabab ababcabab 18: 全部
思路:
next数组的使用
下面给出描述: (i>1)[下标从0开始]
next[i]的意义就是:前面长度为i的字串的【前缀和后缀的最大匹配长度】
那么这题怎么利用这个性质呢?
详细分析一下:【就用上面的第一个例子说明吧】
a b a b c a b a b a b a b c a b a b
0 0 1 2 0 1 2 3 4 3 4 3 4 5 6 7 8 9
len2 = 18 next[len2] = 9
说明对于前面长度为18的字符串,【长度为9的前缀】和【长度为9的后缀】是匹配的, 即上图的蓝色跟红色匹配
也就是整个串的最大前后缀匹配长度就是9了
所以接下来根本不需要考虑长度大于9的情况啦
好了!既然现在只需考虑长度小于9的前后缀匹配情况,那么
[问题就转化成蓝色串的前缀跟红色串的后缀的匹配问题了!!!
又因为蓝串==红串
所以问题又转化成
找蓝串自己的前缀跟自己的后缀的最大匹配了!!!
#include<iostream> #include<cstdio> #include<cstring> #define maxn 400010 using namespace std; int ans[maxn],nxt[maxn],l,cnt; char s[maxn]; void getnxt(){ int i=0,j=-1; nxt[0]=-1; while(i!=l){ if(s[i]==s[j]||j==-1)nxt[++i]=++j; else j=nxt[j]; } } int main(){ while(scanf("%s",s)!=EOF){ l=strlen(s);cnt=0; ans[++cnt]=l; getnxt(); int pos=l; while(1){ if(nxt[pos]==0)break; ans[++cnt]=nxt[pos]; pos=nxt[pos]; } for(int i=cnt;i>=1;i--)printf("%d ",ans[i]); puts(""); } }