HDU 3336 Count the string(KMP+Next数组递推)

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

题目大意:给定一个字符串,求所有前缀串在母串中匹配的数量,包含前缀串本身。

注意一个坑点,虽然没有被坑到。比如aaaaaa,前缀串aa的匹配数目为4个。包括aaaaaa, aaaaaa, aaaaaa, aaaaaa

必须保证与前缀串匹配的串与之不交叉。


先求KMP的next数组,然后遍历所有的前缀串,判断这个前缀串中有几个与匹配数。获得的数目+前缀串总数就可以了。

为了更好地说明问题,我们举abcabcab为例。首先result+=8(所有前缀串(包括本身));

ab 无

abc 无

abca 匹配串为a,匹配数为1   result++

abcab 匹配串为ab,匹配数为1 result++

abc abc 匹配串为abc,匹配数为1 result++


abcabca匹配串为abca, 但是不满足不交叉,即next[i] * 2 > i, 那么就继续对abca进行匹配,得到匹配串a。

所以有abcabca,因为a1=a2, a2=a3,故a1=a3,这个自己感觉一下就可以了。至于中间的a之前已经作为后缀子串计算过了。匹配数为1, result++;


abcabcab 匹配串为ab, 匹配数为1, result++


这样可以枚举出所有的情况。不重复也不缺少,理由是每次枚举的后缀子串的最后一位的下标都不一样。

核心部分还是在next[i] * 2 > i时,应该计算出所有匹配的前缀后缀不交叉的匹配数目。


这个理解还得再看看这个例子:aaaa,匹配串为aaa, 但是next[i] * 2 > i(交叉了),所以取aaa继续操作,得到aa。aa与原串比不超过一半,所以aa aa是一组。但是因为aa的next[2] > 0(很关键),所以继续操作,得到a,a与原串比显然不超过一半,所以aaaa也是一组。所以问题还是在于要一直处理到next <= 0为止。


不懂提问吧,贴代码来,网上的dp没看明白啥意思,不过自己做出来感觉挺好,也挺快。

#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
char str[200005];
int Next[200005];
void getNext(int len)
{
    int i = 0, j = -1;
    Next[0] = -1;
    while(i < len) {
        if(j == -1 || str[i] == str[j]) {
            Next[++i] = ++j;
        }
        else {
            j = Next[j];
        }
    }
}
int main ()
{
    int n, t;
    scanf("%d", &t);
    while (t --) {
        scanf("%d%s", &n, str);
        getNext(n);
        int sum = n, res;
        for (int i = 1; i <= n; i ++) {
            res = Next[i];
            while (res > 0) {
                if(res * 2 <= i) {
                    sum = (sum % 10007 + 1) % 10007;
                }
                res = Next[res];
            }
        }
        printf("%d\n", sum);
    }
    return 0;
}





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章