hdu3336 Count the string

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3336

6

           a  b  a  b  a  b  ‘\0’

下标i:   0  1  2  3  4  5   6

Next: -1  0  0  1  2  3  4

dp:     0  1   1  2  2  3  3

dp[ 1 ]=1表示目前:‘a’出现一次

dp[ 2 ]=1:同上:“ab”

dp[ 3 ]=2表示“abab”一次,“ab”一次

dp[ 6 ]=3表示首字母‘a’在整个的出现次数


/*题解:http://www.cnblogs.com/wuyiqi/archive/2012/01/05/2313746.html
利用kmp中的匹配原理可以完美的解决此题

a---------d-----

-----a---------d

          i    j

如上所示,假设两串字符完全相等,next[j]=i,代表s[1...i]==sum[j-i+1....j],这一段其实就是前缀

i~j之间已经不可能有以j结尾的子串是前缀了,不然next【j】就不是 i 了

设dp【i】:以string[i]结尾的子串总共含前缀的数量

所以dp[i]=dp[next[i]]+1,即以i结尾的子串中含前缀的数量加上前j个字符这一前缀*/

#include <stdio.h>
#include <string.h>
#define MAXN  200002    
#define MOD 10007

char text[MAXN];    
int next[MAXN],dp[MAXN];    

void getNext()    
{    
	int i=0,j=-1;    
	next[0]=-1;    
	while(text[i]!='\0')    
	{    
		if(j==-1||text[i]==text[j])    
		{    
			i++;    
			j++;    
			next[i]=j;    
		}    
		else    
			j=next[j];    
	}    
} 

int main()
{
	int test,n,i,sum;
	scanf("%d",&test);
	while(test--)
	{
		scanf("%d",&n);
		scanf("%s",text);
		getNext();
		sum=0;
		memset(dp,0,sizeof(dp));
		for(i=1;i<=n;++i)
		{
			dp[i]=(dp[next[i]]+1)%MOD;
			sum=(sum+dp[i])%MOD;
		}
		printf("%d\n",sum);
	}
	return 0;
}



#include <stdio.h>
#include <string.h>
#define MAXN  200002    
#define MOD 10007

char text[MAXN];    
int next[MAXN],count[MAXN];    

void getNext()    
{    
	int i=0,j=-1;    
	next[0]=-1;    
	while(text[i]!='\0')    
	{    
		if(j==-1||text[i]==text[j])    
		{  
			count[i]++;//以text[0...i]为前缀的字符串第一次出现
			i++;    
			j++;    
			next[i]=j; 
			if(j>0)//以text[0...j-1]为前缀的字符串出现两次及以上
				count[j-1]++;
		}    
		else    
			j=next[j];    
	}    
} 

int main()
{
	int test,n,i,sum;
	scanf("%d",&test);
	while(test--)
	{
		memset(count,0,sizeof(count));
		scanf("%d",&n);
		scanf("%s",text);
		getNext();
		sum=0;
		for(i=0;i<n;++i)
		{
			sum=(sum+count[i])%MOD;
		}
		printf("%d\n",sum);
	}
	return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值