E - Period HDU - 1358 (找出字串的最小週期)(解釋題意 並且數學邏輯方法解題)
For each prefix of a given string S with N characters (each character has an ASCII code between 97 and 126, inclusive), we want to know whether the prefix is a periodic string. That is, for each i (2 <= i <= N) we want to know the largest K > 1 (if there is one) such that the prefix of S with length i can be written as A K , that is A concatenated K times, for some string A. Of course, we also want to know the period K.
Input
The input file consists of several test cases. Each test case consists of two lines. The first one contains N (2 <= N <= 1 000 000) – the size of the string S. The second line contains the string S. The input file ends with a line, having the number zero on it.
Output
For each test case, output “Test case #” and the consecutive test case number on a single line; then, for each prefix with length i that has a period K > 1, output the prefix size i and the period K separated by a single space; the prefix sizes must be in increasing order. Print a blank line after each test case.
Sample Input
3
aaa
12
aabaabaabaab
0
Sample Output
Test case #1
2 2
3 3
Test case #2
2 2
6 2
9 3
12 4
題意:
給你一個長度為n的字串 讓你分別計算下標為0長度為1........n的字串的週期字串的出現次數k
如果k大於1 輸出長度i 和週期字串的次數k
KMP擴充套件
原理:
設T[i]為前i個字串最小週期為T[i] eg:aabaab T[1]=1 ,T[2]=1,T[3]=3
設next[i]為前i個字元最多匹配前next[i]個字元(不包括自身 這裡的next函式與KMP中函式意思有些更改 這裡的next[i]等效於書上的nextval[i+1]-1) eg:aabaab next[1]=0 next[2]=1 next[3]=0 next[4]=1 next[5]=2 next[6]=3
用語言來表達就是
如果i是個週期字串必定有 I-next[i]=T[next[i]] 其週期T[i]=T[next[i]]
並且如果i-next[i]=T[next[i]] 那麼 i必定是個週期字元週期為T[i]=T[next[i]]
數學邏輯表達
if i-next[i]=T[next[i]] 命題A
then i有不為自身的週期 即T[i]=T[next[i]] 命題B //邏輯表示式 A->B;
if i有不為自身的週期
then i-next[i]=T[next[i]] //邏輯表示式B->A
(得出A==B)
第二個的逆否命題即為
if i-next[i]!=T[next[i]]
then I的週期為自身 //^A->^B
程式碼:
#include<stdio.h>
#include<iostream>
#include<stdlib.h>
#include<string.h>
using namespace std;
const int maxn=1001000;
int net[maxn];//net[j] 下標為j的失配後 匹配到下標net[j] 即前j個字串最大匹配為net[j]個
int T[maxn];//T[i]代表最小週期為T[i]
void Get_nextval(int *net,char *str)//這是求i以及i之前的最大匹配數目
{
int len=strlen(str);
net[0]=-1;
int j=0,k=-1;
while(j<len)//j為字串的下標
{
if(k==-1||str[j]==str[k])
net[++j]=++k;
else
k=net[k];
}
}
int main()
{
char str[maxn];
int cas=0;
int len;
while(scanf("%d",&len)&&len)
{
scanf("%s",str);
Get_nextval(net,str);
printf("Test case #%d\n",++cas);
T[0]=0;
T[1]=1;
int k;
for(int i=2;i<=len;i++)
{
k=net[i];
if(i-k==T[k])
{
T[i]=T[k];
cout<<i<<" "<<i/T[i]<<endl;
}
else
T[i]=i;
}
cout<<endl;
}
}