hdu3336——循环节+next数组性质

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

It is well known that AekdyCoin is good at string problems as well as number theory problems. When given a string s, we can write down all the non-empty prefixes of this string. For example:
s: "abab"
The prefixes are: "a", "ab", "aba", "abab"
For each prefix, we can count the times it matches in s. So we can see that prefix "a" matches twice, "ab" matches twice too, "aba" matches once, and "abab" matches once. Now you are asked to calculate the sum of the match times for all the prefixes. For "abab", it is 2 + 2 + 1 + 1 = 6.
The answer may be very large, so output the answer mod 10007.

Input

The first line is a single integer T, indicating the number of test cases.
For each case, the first line is an integer n (1 <= n <= 200000), which is the length of string s. A line follows giving the string s. The characters in the strings are all lower-case letters.

Output

For each case, output only one number: the sum of the match times for all the prefixes of s mod 10007.

Sample Input

1
4
abab

Sample Output

6

题目翻译:

众所周知,AekdyCoin擅长弦问题以及数字理论问题。当给定一个字符串 s 时,我们可以记下此字符串的所有非空前缀。例如:s:"abab"‎

‎前缀是:"a"、"ab"、"aba"、"abab"‎
‎对于每个前缀,我们可以计算它在 s 中匹配的时间。因此,我们可以看到前缀"a"匹配两次,"ab"匹配两次,"aba"匹配一次,"abab"匹配一次。现在,系统将要求您计算所有前缀的匹配次数总和。对于"abab",它是 2 + 2 + 1 + 1 = 6。‎
‎答案可能非常大,因此输出答案 mod 10007。‎

‎输入‎

‎第一行是单个整数 T,指示测试用例的数量。‎
‎对于每种情况下,第一行是整数 n (1 <= n <= 200000),这是字符串 s 的长度。下面有一行给出字符串 s。字符串中的字符都是小写字母。‎

‎输出‎

‎对于每种情况下,只输出一个数字:s mod 10007 的所有前缀的匹配时间之和。

 

这个题很不好想,后来看的kuangbin的博客才发现可以用dp做,dp[i]=dp[next[i]]+1,自己想想应该会好点。

next数组的值就是记录当前位置向前多少个和这个字符串开头多少个相等,有了这样我们只要记录每个next这对应有多少个,然后加上n个自身的一个匹配就行了。——来自大牛。

#include <iostream>
using namespace std;
const int maxn=5e5+7;
const int mod=1e4+7;
string str;
int nxt[maxn];
int len;
void getnext(){
	nxt[0]=-1;
	int j=0,k=-1;
	while(j<len){
		if(k==-1||str[j]==str[k]){
			j++;
			k++;
			nxt[j]=k;
		}
		else k=nxt[k];
	}
}
int main(int argc, char** argv) {
	int T;
	cin>>T;
	while(T--){
		cin>>len>>str;
		getnext();
		int ans=0;
		for(int i = 1;i<=len;++i){
			int temp=nxt[i];
			while(temp){
				ans=(ans+1)%mod;
				temp=nxt[temp];
			}
		}
		printf("%d\n",(ans+len)%mod);
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值