POJ1961_Peroid_KMP_求最多的子串重复次数

/*

吐槽君又来吐槽了,额= =这就是我两天来学习KMP的成果,水了一道水题,还是照着模版,看着题解写的=i=唯一的成就就是我植物大战僵尸的水平又更上一层楼,对自己无语了,暑假集训俨然要过半了,自己期待的蜕变却越来越远,希望明天能有新变化,今晚早睡

*/

言归正传:

题意:

给一个字符串长为n,i从1到n,对与每一个i,找出从str[0]到str[i-1]内的一个最短子串s,使得当前串是由子串s循环k次组成的,输出当前i与k,当k<=1时不输出

 

题解:

第一次做KMP,看了很多博客和ppt讲解,现在还是晕晕乎乎的= =,这道题是考察对next数组的理解与运用,我是参照POJ2406的题解做的,那个题就是求s最多能拆成几个子串,这里只不过不止求s,还把所有长度的母串都求了一遍

题意转化为,找到最小的L,使得s[L]....s[n-1]=s[0]......s[n-1-L]

在s串后添加\0,则L=strlen(s)-next[n];//这里需要好好理解一下

例:

s:   abababab

              abababab

next[8]=6;

L=2;

 

求next的函数是照着维基百科上面给的模版写的

伪代码如下:

/*

algorithmkmp_table:

  input:

    an array of characters, W (the word to be analyzed)

    an array of integers, T (the table to be filled)

  output:

    nothing (but during operation, it populates the table)define variables:

    an integer, pos ← 2 (当前要计算T数组元素)

    an integer,cnd ← 0 (辅助变量,满足

    W[0..cnd-1]=W[pos-cnd-1..pos-2])

  let T[0] ← -1, T[1] ← 0

while pos is less than the length of W, do:

  (first case: the substring continues)

  if W[pos - 1] = W[cnd],
 
letcndcnd + 1, T[pos] ←cnd, pos ← pos + 1

  (second case: it doesn't, but we can fall back)

  otherwise,ifcnd > 0,

    letcnd ← T[cnd]

  (third case: we have run out of candidates. Notecnd = 0)

  otherwise,let T[pos] ← 0, pos ← pos + 1

 

*/

原题题目:

Period
Time Limit: 3000MS Memory Limit: 30000K
Total Submissions: 11016 Accepted: 5075

Description

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 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

Run IDUserProblemResultMemoryTimeLanguageCode LengthSubmit Time
11772450chengtbf1961Accepted7964K719MSC++945B2013-07-12 22:09:04

代码:

 

#include<stdio.h>
#include<string.h>
#define N 1000005

int count,n;
int str[N];
int next[N];
void get_next()
{
	next[0]=-1;next[1]=0;
	int pos=2;//用来记录数组下标
	int cnd=0;//辅助变量,满足str[0]......str[cnd-1]=str[pos-cnd-1].........str[pos-2]
	while (pos<=n)
	{
		if (str[pos-1]==str[cnd])
		{
			cnd++;
			next[pos]=cnd;
			pos++;
		}
		else if(cnd>0)
		{
			cnd=next[cnd];
		}
		else
		{
			next[pos]=0;
			pos++;
		}
	}
}
	
int main()
{
	int i,len;
	char temp;
	count=0;
	while (1)
	{
		count++;
		scanf("%d",&n);
		if (n==0)
		{
			break;
		}
		scanf("%c",&temp);
		for ( i = 0; i <n; i++)
		{
			scanf("%c",&temp);
			str[i]=temp-'a'+1;
		}
		get_next();
		printf("Test case #%d\n",count);
		for ( i = 1; i <=n ; i++)
		{
			len=i-next[i];//此处len表示在str[0]......str[i-1]内重复的最短子串
			if (i%len==0 && i/len>=2)
			{
				printf("%d %d\n",i,i/len);
			}
		}
		printf("\n");
	}
	return 0;

}


 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值