[NOI2014][洛谷P2375]动物园(KMP)

题面

https://www.luogu.com.cn/problem/P2375

题解

可以构建该字符串的一棵next树,即每个点向自己的next连一条边。
如果没有“不重叠”的限制条件,所求num[i]即为next树上点i的深度。
有该条件后,只需要维护位置mid,设当前dfs到点i,则mid为i到根路径上,<=i/2的最大者
所求num[i]即为dfs到i时对应mid的深度
mid全程移动的路程小于i全程移动的路程O(n)

代码

#include

using namespace std;

#define N 1000000
#define ll long long
#define mod 1000000007 
#define rg register

inline int read(){
    int s = 0,ww = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-')ww = -1;ch = getchar();}
    while('0' <= ch && ch <= '9'){s = 10 * s + ch - '0';ch = getchar();}
    return s * ww;
}

int n,cnt;
char s[N+5];
int head[N+5],nx[N+5];

struct node{
    int next,des;
}e[N+5];

inline void addedge(int a,int b){
    cnt++;
    e[cnt].des = b;
    e[cnt].next = head[a];
    head[a] = cnt;
}

inline void prepro(){
    nx[1] = 0;
    int p = 0;
    for(rg int i = 2;i <= n;i++){
        while(p && s[p+1] != s[i])p = nx[p];
        if(s[p+1] == s[i])p++;
        nx[i] = p;
    }
}

int S[N+5],dep[N+5],num[N+5];
int top,mid;

inline void dfs(int u){
    S[++top] = u;
    if(u)while((S[mid+1]<<1) <= u)mid++;
    num[u] = dep[S[mid]];
    for(rg int i = head[u];i;i = e[i].next){
        int v = e[i].des;
        dep[v] = dep[u] + 1;
        int temp = mid;
        dfs(v);
        mid = temp;
    }
    top--;
}

int main(){
    int T = read();
    while(T--){
        memset(head,0,sizeof(head));
        cnt = 0;
        scanf("%s",s + 1);
        n = strlen(s + 1);
        prepro();
        for(rg int i = 1;i <= n;i++)addedge(nx[i],i);
        top = mid = 0;
        dfs(0);
        ll ans = 1;
        for(rg int i = 1;i <= n;i++)ans = ans * (ll)(num[i] + 1) % mod;
        cout << ans << endl;
    }
    return 0;
}

你可能感兴趣的:([NOI2014][洛谷P2375]动物园(KMP))