[NOI2014] 动物园

[NOI2014] 动物园

link

试题分析

首先一定与kmp数组有关。
然后求出每个位置最长的题目要求的数组num。
然后考虑这两个数组怎么统计。
由于num前缀与后缀一样,那么只需要统计前i个的前缀等于后缀无要求的数量。
这个东西我们可以直接从前后缀递推出来。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<algorithm>
 
using namespace std;
#define LL long long
 
inline int read(){
    int x=0,f=1; char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}
const int INF = 2147483600;
const int MAXN = 2000010;
const LL Mod = 1000000007;
 
int nxt[MAXN+1],cnt[MAXN+1],num[MAXN+1];
char str[MAXN+1]; int T;
 
int main(){
    //freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
    T=read();
    while(T--){
        memset(num,0,sizeof(num));
        memset(nxt,0,sizeof(nxt)); nxt[0]=-1; num[0]=-1;
        LL ans=1;
        scanf("%s",str+1); int len=strlen(str+1);
        for(int i=1;i<=len;i++){
            int j=i-1,k=i-1; while(j>-1){
                if(str[i]==str[nxt[j]+1]) {nxt[i]=nxt[j]+1; break;}
                else j=nxt[j];
            } cnt[i]=cnt[nxt[i]]+1;
            while(k>-1){
                if(str[i]==str[num[k]+1]) {num[i]=num[k]+1; break;}
                else k=num[k];
            } while(num[i]>(i>>1)) num[i]=nxt[num[i]];
            ans=1LL*ans*(cnt[num[i]]+1)%Mod;
        } printf("%lld
",ans);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/wxjor/p/9515898.html