「UVA1328」Period 解题报告

English题面

题意:

给你一个长度为n的字符串,依次取字符串前i个(前缀),如果前缀由k(k>0)个相同真子串构成,那么输出i和k

直到n为0结束,每组数据后要有一行空白

思路:

KMP+一点点判断

其实这道题并不是很难

可以先用KMP求出最长的s[1~i]的前缀和后缀的真子串的长度j

话说的有点复杂,分开来理

1、真子串:

不是字符串本身的子串

2、是s[1~i]的前缀和后缀:

aabaab为例

aabaab

aabaab

aab是aabaab的前缀,又是后缀

j=3

两种条件下:

以aaa为例

就应该是

aaa

aaa

aa是aaa的前缀&后缀&真子串

j=2

判断方法

if(i%(i-j)==0) //说明循环的子串长度为i-j,循环次数为i/(i-j)

证明:

RT:

(ecause) l=r

( herefore) ①=①,②=②,③=③

( herefore) ①=②=③

其他情况无论多少都可以这样 连等,只要i-j能够整除i那么就是成立的

Code:

#include<bits/stdc++.h>
using namespace std;
string s;
int n,t;
int len,cur;
int p[1000010];
int read()
{
	int s=0;
	char c=getchar();
	while(!isdigit(c))
		c=getchar();
	while(isdigit(c))
	{
		s=(s<<1)+(s<<3)+c-'0';
		c=getchar();
	}
	return s;
}
int main()
{
	int i,j;
	n=read();
	while(n)
	{
		printf("Test case #%d
",++t);
		cin>>s;
		len=s.size();
		for(i=len;i;i--)
			s[i]=s[i-1];
		for(i=2,j=0;i<=len;i++)//KMP大法
		{
			while(j&&s[i]!=s[j+1])//求前缀的那个东东
				j=p[j];
			if(s[i]==s[j+1])
				j++;
			p[i]=j;
			if(j>=(i>>1)&&i%(i-j)==0)//判断一下
				printf("%d %d
",i,i/(i-j));
		}
		printf("
");
		n=read();
	}
	return 0;
}

友情链接

KMP百度百科

【模板】KMP字符串匹配

原文地址:https://www.cnblogs.com/hovny/p/10136197.html