题意:问你所有前缀包含本身出现的次数是多少、
首先,不得不在这给大家叙说一个问题,那就是这道题的数据很弱,很多有BUG的代码,也能过、在这,还是希望按照正确的思路,正确的做法来AC这道题、
对于这道题,我本身也是做过了这道题的,其实我刚开始的思路完全错误,不过我AC了、 我朋友在做这道题的时候,问了我一组数据,就是abababab这种情况的时候输出20、
思路:这道题的思路是KMP+DP的思想,那么,首先我们要知道的是,DP只是一种思想,动态规划,是要从曾经求过的不需要重新求取,直接提取出来加入我当前想要求值的,这样降低了时间复杂度,那么KMP呢? 一定能确定的是,KMP用到的也是动态规划的思想、
好,首先一定要了解到next数组的思想、以及两大要素 前后缀相同,和最大循环次数最小循环节的思想、 对于next数组,无需多提,next[i]为在第i个位置前缀与后缀相同的最大值、next[i]里面的不仅为前后缀相同的最大值,也表示了如果当前位置不同,我需要回溯到哪个最优位置来无需匹配我没必要的匹配、
首先我们要知道的是dp[i]里面存的值到底是什么?,dp[i] 表示的意义是,在字符串中第i个位置时,next[i]表示的是我最大的前后缀相同的长度,那么我们可以求解出,这个前后缀出现的次数一定是2次对吧? 而这个前缀,也就是后缀中,也有可能有其他的前缀,在abababab中假设此时i在第三个b的位置时,他的前缀为abab 后缀为abab,此时这个后缀中包含了a,ab,aba,abab 这四个整个字符串的前缀对吧、 那么当我求第i个位置的时候,我只需要找到在dp[i]也就是dp[next[i]]的位置我之前已经求过的前缀中的包含前缀的值、只需在dp[i]也就是dp[next[i]]加上1 变为dp[i]+1=dp[next[i]]+1、 为什么要加上这个1呢? 首先dp[i]表示的是当前前缀时我之前求结果的值,+1也就是加上前缀为0~i 这个整个字符串的子串、
针对 abababab
next[i]-100123456
dp[i] 11223344
答案便为dp中所有的数值相加、 如果自己还不是很理解的话,可以模拟一下,多模拟几次就懂了、无论是怎样学习,当学习新知识的时候,我们都要自己动手来模拟过程,因为这样会更加的使我们的思路清晰,对新知识理解的更深刻、
AC代码:
#include<cstdio>
#include<cstring>
const int maxn=100100*2;
const int mod=10007;
char T[maxn];
int next[maxn];
int dp[maxn];
int lent,t;
int sum;
void get_next()
{
memset(next,0,sizeof(next));
memset(dp,0,sizeof(dp));
int i=0; int j=-1; next[0]=-1; sum=0;
while(i<lent){
if(j==-1||T[i]==T[j])
next[++i]=++j;
else
j=next[j];
}
}
int main()
{
scanf("%d",&t);
while(t--){
scanf("%d %s",&lent,T);
get_next();
for(int i=1;i<=lent;i++){
dp[i]=dp[next[i]]+1;
sum+=dp[i]; sum%=mod;
}
printf("%d\n",sum%mod);
}
return 0;
}