hdu 3336Count the string(KMP变形,求前缀出现的次数和)

题目链接:【hdu 3336】

t组测试数据,输入长为n的字符串s[n](1<=n<=200000),求s[]的每一个前缀在s[]中出现的总次数

例如:s[] = ababa

前缀        次数

a               3

ab             2

aba           2

abab         1

ababa       1

====>    输出9

先用KMP求出数组f[n],对于ababa,相应的f[n] = {0,0,1,2,3}

f[i] = x   ===>  s[1~x]与s[x~i]完全相等,那么到x为止,在s[1~x]出现过的以s[x]为结尾的前缀一定会在s[x~i]中

例如:s[] = ababa(我们就专注于结尾是a的,结尾是b的先不用去管它) 

图中字符串下面的红线表示的是到i为止,出现的以s[i]为结尾的前缀


#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
using namespace std;
#define mod 10007
#define inf 200100
char s[inf];
int t, n, f[inf], dp[inf], ans;
void getf()
{
	memset(f, 0, sizeof(f));
	int j=0;
	for(int i=2; i<=n; i++)
	{
		while(j&&s[i]!=s[j+1]) j = f[j];
		f[i] = (s[i]==s[j+1] ? ++j:0);
	}
}
int main()
{
	scanf("%d", &t);
	while(t--)
	{
		memset(dp, 0, sizeof(dp));
		ans = 0;
		scanf("%d%s", &n, s+1);
		getf();
		for(int i=1; i<=n; i++)
		{
			dp[i] = (dp[f[i]]+1) % mod;
			ans = (ans+dp[i]) % mod;
		}
		printf("%d\n", ans);
	}
	return 0;
} 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值