题目链接: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
#include
#include
#include
#include
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;
}