POJ2406 & POJ1961 详细解题思路和AC程序 KMP算法变种

原创 2015年07月09日 00:48:00

poj2406

题目大意:

给出一个字符串s,求其最短的子串a,使得s=a^n(即n个a相连),输出n。s的长度小于10^6。


Sample Input

abcd
aaaa
ababab
.

Sample Output

1
4
3




本题可以用kmp算法来做。

先算出next数组。有些KMP算法的代码中next[i]代表的是s[i+1]匹配不上时下一个位置,有些代码代表的是s[i]匹配不上时,本人用后者,即next数组要求到'\0'那位。


len表示s的长度(不包括'\0'),那么如果确实有长度非len的解的话,该子串的最小长度一定为(len-next[len])。

以上不证明了(因为不会证),参考kmp算法的原理脑补一下:p

但长度为(len-next[len])的子串不一定真的是解。比如:abcab,len-next[len]=3,长度为3的串abc或者cab显然不是解

所以需要判断len%(len-next[len])==0是否成立。


够了吗? 那么是否有必要扫描一遍s,判断是否s中存在的确实是len/(len-next[len])个该子串呢?

够了。


如下图,表示len==12,next[len]==8时的情景,len-next[len]==4,可以发现s即为3个长度为4的子串构成的



参考程序:

#include <stdio.h>
#include <stdlib.h>
char s[1000010];
int next[1000010];

int kmp_next(char s[])
{
	int k=-1,j=0;
	next[j]=k;

	while (s[j])
	{
		if (k==-1 || s[k]==s[j])
		{
			k++;
			j++;
			if (s[k]==s[j])
				next[j]=next[k];
			else
				next[j]=k;
		}
		else k=next[k];
	}
	return j;
}

int main()
{
	int len,i,ans,flag,j;
	scanf("%s",s);
	while (s[0]!='.')
	{
		len=kmp_next(s);

		ans=(len-next[len]);
		if (len%ans!=0)
			ans=len;

		printf("%d\n",len/ans);
		scanf("%s",s);
	}
	return 0;
}


POJ1961


题目大意:

给出一个字符串的长度和字符串s,对于其所有的前缀,设其长度为i,求最大的k(k>=2),使a^k=substring(s,0,i),若存在这样的k,输出i,k

输出所有满足的i,k对


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




跟上题差不多,不过这回需要对next数组进行遍历。

同时注意求next数组的时候

			if (s[k]==s[j])
				next[j]=next[k];
			else
				next[j]=k;
如果有该优化的话,该优化得去掉,改成:

  next[j]=k;

原因见kmp算法原理




参考程序:



#include <stdio.h>
#include <stdlib.h>

char s[1000010];
int next[1000010];

void kmp_next(char s[])
{
	int k=-1,j=0;
	next[j]=k;

	while (s[j])
	{
		if (k==-1 || s[k]==s[j])
		{
			k++;
			j++;
			next[j]=k;
		}
		else k=next[k];
	}
}

int main()
{
	int tt,len,i,l,j=0;
	scanf("%d",&len);
	gets(s);
	while (len!=0)
	{
		gets(s);
		kmp_next(s);

		printf("Test case #%d\n",++j);
		for (i=2;i<=len;i++)
		{
			l=i-next[i];
			if (i%l==0 && i/l>1)
				printf("%d %d\n",i,i/l);
		}

		printf("\n");
		scanf("%d",&len);
		gets(s);
	}
	return 0;
}



需要做更基础的kmp题的可以去做poj3461,poj2752




版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

KMP算法的经典例题(poj 3461、poj 2752、poj 2406、poj1961)

传送门:POJ-3461 最简单的KMP题,找出第一个字符串在第二个字符串中出现次数。 #include #include #include #define Memset(x, a) mems...

KMP算法的练习题(poj 3461、poj 2752、poj 2406、poj 1961)

//poj 3461 Oulipo 最简单的KMP题,找出第一个字符串在第二个字符串中出现次数。 #include #define M 1000010 char s[M],t[M]; int next...
  • lalor
  • lalor
  • 2012年03月15日 22:38
  • 6500

poj 1961 KMP算法的应用

多久了,,,多久了,,,,两天了,,,,终于ac了一道题,,还是一道水题。。。。。。悲剧,,,,杭电上的一道题,,,一直看不懂题意,看不懂,,纠结,,,,就这样一直看了两天,,还是不懂,,,受打击了,...
  • wmn_wmn
  • wmn_wmn
  • 2011年11月09日 21:47
  • 791

poj 2406 Power Strings(kmp算法)

题目链接:http://poj.org/problem?id=2406 Power Strings Time Limit: 3000MS   M...

KMP算法、next数组与前缀中的周期(相关题目:Power strings, poj2406)

在一个大的字符串S中查找字符串T,naive的算法时间复杂度为O(s * t)(这里s与t代表S的长度与T的长度);而应用KMP,时间复杂度为O(s + t)。 KMP算法的核心在于next...
  • mach7
  • mach7
  • 2014年02月26日 13:16
  • 2501

HihoCoder第三周与POJ2406:KMP算法总结

HihoCoder第三周: 输入 第一行一个整数N,表示测试数据组数。 接下来的N*2行,每两行表示一个测试数据。在每一个测试数据中,第一行为模式串,由不超过10^4个大写字母组成,第二行为原串...

[kmp算法next数组的应用][poj1961]Period

[kmp算法next数组的应用][poj1961]Period原题传送门DescriptionFor each prefix of a given string S with N characters...

Period poj 1961 KMP算法的运用

Period Time Limit: 3000MS   Memory Limit: 30000K Total Submissions: 11938   Accept...

kmp算法 和例题 poj1961

题目   http://poj.org/problem?id=1961 刚开始做这个不知道什么是kmp算法    自己看了很多书籍介绍  没看懂   最后还是看课本知道了一点点 首先我来介绍kmp...

kmp算法练习 poj 1226 poj 1961

poj 1226 题目大意:给出一组字符串,要你求出这些字符串的最长公共子串的长度,公共子串可以正序或逆序匹配 解题思路:kmp枚举,枚举第一个字符串的每个子串的正序和逆序,与其余的字符串匹配看是...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:POJ2406 & POJ1961 详细解题思路和AC程序 KMP算法变种
举报原因:
原因补充:

(最多只允许输入30个字)