【POJ 2406】Power Strings

来源:互联网 发布:php培训机构哪家好 编辑:程序博客网 时间:2024/06/05 20:22

问题描述
Given two strings a and b we define a*b to be their concatenation. For example, if a = “abc” and b = “def” then a*b = “abcdef”. If we think of concatenation as multiplication, exponentiation by a non-negative integer is defined in the normal way: a^0 = “” (the empty string) and a^(n+1) = a*(a^n).
输入
Each test case is a line of input representing s, a string of printable characters. The length of s will be at least 1 and will not exceed 1 million characters. A line containing a period follows the last test case.
输出
For each s you should print the largest n such that s = a^n for some string a.
样例输入
abcd
aaaa
ababab
.
样例输出
1
4
3
算法讨论
KMP算法:
我们用两个指针i和j分别表示,A[i-j+ 1..i]与B[1..j]完全相等。也就是说,i是不断增加的,随着i的增加j相应地变化,且j满足以A[i]结尾的长度为j的字符串正好匹配B串的前 j个字符(j当然越大越好),现在需要检验A[i+1]和B[j+1]的关系。当A[i+1]=B[j+1]时,i和j各加一;什么时候j=m了,我们就说B是A的子串(B串已经整完了),并且可以根据这时的i值算出匹配的位置。当A[i+1]<>B[j+1],KMP的策略是调整j的位置(减小j值)使得A[i-j+1..i]与B[1..j]保持匹配且新的B[j+1]恰好与A[i+1]匹配(从而使得i和j能继续增加)。
程序代码

j:=0;for i:=1 to n dobegin       while (j>0) and (B[j+1]<>A[i]) do j:=P[j];       if B[j+1]=A[i] then j:=j+1;       if j=m then       begin          writeln('Pattern occurs with shift ',i-m);          j:=P[j];       end;end;

预处理:
我们可以通过P[1],P[2],…,P[j-1]的值来获得P[j]的值。对于B=”ababacb”,假如我们已经求出了P[1],P[2],P[3]和P[4],看看我们应该怎么求出P[5]和P[6]。P[4]=2,那么P [5]显然等于P[4]+1,因为由P[4]可以知道,B[1,2]已经和B[3,4]相等了,现在又有B[3]=B[5],所以P[5]可以由P[4]后面加一个字符得到。P[6]也等于P[5]+1吗?显然不是,因为B[ P[5]+1 ]<>B[6]。那么,我们要考虑“退一步”了。我们考虑P[6]是否有可能由P[5]的情况所包含的子串得到,即是否P[6]=P[ P[5] ]+1。P[5]=3是因为B[1..3]和B[3..5]都是”aba”;而P[3]=1则告诉我们,B[1]和B[5]都是”a”。既然P[6]不能由P [5]得到,或许可以由P[3]得到(如果B[2]恰好和B[6]相等的话,P[6]就等于P[3]+1了)。显然,P[6]也不能通过P[3]得到,因为B[2]<>B[6]。事实上,这样一直推到P[1]也不行,最后,我们得到,P[6]=0。
其实,KMP的预处理本身就是一个B串“自我匹配”的过程。它的代码和上面的代码神似:

P[1]:=0;j:=0;for i:=2 to m dobegin       while (j>0) and (B[j+1]<>B[i]) do j:=P[j];       if B[j+1]=B[i] then j:=j+1;       P[i]:=j;end;

至于本题,和上一题十分类似,把KMP算法预处理部分拉过来解题即可。易得,若l能被p[l]整除,则说明它符合重复条件。

#include<cstdio>#include<cstring>using namespace std;char st[1000000];int p[1000000];int main(){    while (gets(st),st[0]!='.')    {        int l=strlen(st);        p[0]=-1;        int j=-1;        for (int i=1;i<l;i++)        {            while ((j>-1)&&(st[j+1]!=st[i]))                j=p[j];            if (st[j+1]==st[i])                j++;            p[i]=j;        }        int s=1;        if (l%(l-p[l-1]-1)==0)            s=l/(l-p[l-1]-1);        printf("%d\n",s);    }    return 0;}

这里写图片描述
Pixiv ID:58639865

原创粉丝点击