HDU 3336 Count the string

7 篇文章 0 订阅

题意:问你所有前缀包含本身出现的次数是多少、 

首先,不得不在这给大家叙说一个问题,那就是这道题的数据很弱,很多有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;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值