【NOI2014】动物园 kmp

来源:互联网 发布:阿里云cdn怎么收费 编辑:程序博客网 时间:2024/05/16 00:16

题目链接: http://uoj.ac/problem/5

题意: 中文题目

解法:
如果num数组记载的前后缀允许重叠,是可以在递推next数组时顺路O(L)求出来的,这一步还算比较简单。
重点在于如何通过这个允许重叠的num数组求出不允许重叠时对应的num值。方法是让整个串再自己匹配自己一次,不过每次匹配时,如果j+1>(i+1)/2,即发现有重叠时,也要沿着next走。如果匹配成功,即str[i]==str[j],则说明i的num值应该是num[j]的值(因为也是这样递推算过来的),相乘即可;若匹配不成功,说明此时i的num值为0,答案要乘上1所以可以忽略。

//NOIP 2014#include <bits/stdc++.h>using namespace std;const int maxn = 1000010;const int mod = 1000000007;char s[maxn];int fail[maxn], nxt[maxn];long long ans;int main(){    int t; scanf("%d", &t);    while(t--){        ans = 1;        scanf("%s", s+1);        int len = strlen(s+1);        int j = 0;        memset(fail, 0, sizeof(fail));        memset(nxt, 0, sizeof(nxt));        nxt[1] = 1;        for(int i = 2; i <= len; i++){            while(s[j+1] != s[i] && j > 0) j = fail[j];            if(s[j+1] == s[i]) j++;            fail[i] = j;            nxt[i] = nxt[j]+1;        }        j = 0;        for(int i = 2; i <= len; i++){            while(s[j+1]!=s[i]&&j>0) j = fail[j];            if(s[j+1]==s[i]) j++;            while((j<<1)>i&&j>0) j = fail[j];            ans = (ans*(nxt[j]+1))%mod;        }        printf("%lld\n", ans);    }    return 0;}
0 0
原创粉丝点击