HDU 3336 Count the string(KMP+DP)

题目链接:hdu3336

题目大意:求字串中【前缀+跟前缀相同的子串】的个数?

Sample Input
1
4
abab

Sample Output
6

abab:包括2个a,2个ab,1个aba,1个abab


思路: KMP + DP

kmp思想:

      对字符串进行预处理,记录与当前位置i后缀相同的“最近”位置,用next[i]记录,保证 s[1 .. i] 中 s[i - next[i] + 1 .. i] 与 s[1 .. next[i]] 是相同的, 以便在某处字符不匹配时,不用重新从头判断一遍,只要从对应的next[i]即可, 因为中间有部分与自身重叠,减少了不必要的判断,实现见代码。
   
    例1:          
          i :     1234567
      字符串 :    abcabab 
       next[i] :     0001212
     例2:
            i  :    12345678
      字符串 :    abababab 
       next[i] :    00123456

      例3:
           i :     123456789
     字符串:     ababcdabd 
       next[i]:     001200120
 DP: 
  cns[]数组:以 i 结尾的串中所有前缀的计数和
   状态转移方程:  cns[i] = cns[next[i]] + 1;
      
          i :     123456
     字符串:    ababab   
        cns[i]:    112233

 比如当i等于5时,ababa中后面的aba与前面的aba重叠,  

以第三个a为结尾的前缀总数对应于前面的aba的前缀数+1(ababa)

#include <stdio.h>
#include <algorithm>
#include <iostream>
#include <string.h>
using namespace std;
#define maxn 200020
#define mod 10007
char s[maxn];
int nexts[maxn];
int n,m;
int dp[maxn];
void getnexts()//因为s字符串的前缀匹配t字符串的后缀 所以把s作为匹配的字符串 求nexts
{
	int j=0;
	int k=-1;
	nexts[0]=-1;
	while(j<m)
	{
		if(k==-1||s[j]==s[k])
		{
			j++;k++;
			nexts[j]=k;
		}
		else k=nexts[k];
	}
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%s",&m,s);
		getnexts();
		dp[0]=0;
		int ans=0;
		for(int i=1;i<=m;i++)
		{
			dp[i]=dp[nexts[i]]+1;
			dp[i]%=mod;
			ans+=dp[i];
			ans%=mod;
		}
		printf("%d\n",ans);
	}
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值