BZOJ3670 [Noi2014]动物园

kmp。

字符串的题都好难啊。

进行一次kmp,用一个dp[i]数组记录前缀中前缀匹配后缀的数量(算本身)

同时进行一个类似kmp的过程,用变量k表示满足长度限制后,最长的匹配前缀和后缀。

则num[i]=dp[k]。为什么呢?

首先变量k满足了长度限制,dp数组记录了匹配串的数量。dp多的1正好可以充当目前的前缀和后缀。

字符串的题都好难啊。。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
const int maxn = 1000000 + 10;
const LL mod = 1000000007;

char a[maxn];
int next[maxn];
LL dp[maxn],res;
int T,n,j,k;

int main() {
    //freopen("ex_zoo2.in","r",stdin);
    scanf("%d",&T);
    while(T--) {
        scanf("%s",a+1);
        n=strlen(a+1);
        res=1;
        memset(next,0,sizeof(next));
        memset(dp,0,sizeof(dp));
        j=k=0; dp[1]=1;
        
        for(int i=1;i<n;i++) {
            while(a[i+1]!=a[j+1] && j) j=next[j];
            if(a[i+1]==a[j+1]) j++;
            next[i+1]=j;
            dp[i+1]=dp[j]+1;
            while(k && a[i+1]!=a[k+1]) k=next[k];
            if(a[i+1]==a[k+1]) k++;
            while(k>(i+1)/2) k=next[k];
            res*=(dp[k]+1); 
            res%=mod;            
        }
        for(int i=1;i<=n;i++) printf("%d %d\n",next[i],dp[i]);
        printf("%lld\n",res);
    }    
    return 0;
}

posted @ 2016-06-30 23:43  invoid  阅读(202)  评论(0编辑  收藏  举报