加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

HDOJ Monthly Contest – 2010.03.06 1004 kmp dp

(2010-03-08 22:59:00)
标签:

杂谈

分类: 动态规划

  题目描述:给一个字符串,如abab,它的前缀有a,ab,aba,abab,第一个前缀在字串中出现次数为2,第二个为2,第三个和第四个都为1,其和为6.给一个字符串,求和。

  方法:只要对每个位置i求出前面能匹配的以str[i]结尾的前缀的个数,用dp[i]表示前缀0...i - 1出现的次数

  即dp[next[i]] = dp[i],保证了不会重复,且具有传递性,dp[next[next[i]]] = dp[next[i]也自然包括了dp[i]。

首先对串做kmp,获得next函数,next[i]的真正意义所在 s[i-next[i] 1,i]==s[0,next[i]-1]
那么我们可以从后往前,不断回溯,把后面出现的模式往前累加,即dp[next[i]-1] =dp[i];初始dp值全设为1,因为从开始到i都是自身一个匹配。

代码:#include<iostream>
#include<string>
using namespace std;
char x[200005];
int next[200005];
int dp[200005];
int cnt;
void GetNext(int len)
{
    int i = 0, j = -1;
    next[0] = -1;
    while(i < len)
        if (j == -1 || x[i] == x[j])
        {
            i , j ;
            next[i] = j;
        }
        else
            j = next[j];
}
int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        cnt = 0;
        int len1;
        scanf("%d", &len1);
        scanf("%s", x);
        GetNext(len1 1);
        for(int i = 1; i <= len1; i )
            dp[i] = 1;
        for(int i = len1 ; i >= 0; i--)
            if (next[i] != -1 && next[i] != 0)
                dp[next[i]] = dp[i];
        for(int i = 1; i <= len1; i )
        {
            cnt = dp[i];
            if (cnt >= 10007)
                cnt %= 10007;
        }
        printf("%d\n", cnt);
    }
}

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有