zoukankan      html  css  js  c++  java
  • NOI2014 动物园

    传送门

    KMP好题啊……

    题中要求我们求出长度不超过原字符串一般的相同的前后缀的个数。其实这个用做前面几道题的思路大致猜测一下……可以发现,我们只要从这个字符串一直往它的next递归,那么我们就可以获得一系列的公共前后缀,而且只要当next的长度<=原长度的一半的时候答案即合法。(不能继续递归,否则就重复计算了)

    每个点可以获取的相同的前后缀个数可以通过kmp预处理出来,我们只要让ans[i] = ans[j]+1,(其中next[i] = j),因为在i向j跳的时候相当于获取了一个长度为j的公共前后缀的贡献。

    不过我们如果这样一直递归,遇到无良数据(比如200000个a),你就T飞了,因为每次递归只会减少1的长度。解决的方法是,我们在计算的时候也像KMP一样,每次不更新j的位置,使之一直呆在小于i的一半的位置(因为你肯定是要小于i的一半才合法),这样可以避免许多无用的递归,就可以在线性时间之内求解了。

    看一下代码。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #include<set>
    #include<queue>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define enter putchar('
    ')
    
    using namespace std;
    typedef long long ll;
    const int M = 10005;
    const int N = 1000005;
    const ll mod = 1000000007;
    
    int read()
    {
        int ans = 0,op = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
        if(ch == '-') op = -1;
        ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
        ans *= 10;
        ans += ch - '0';
        ch = getchar();
        }
        return ans * op;
    }
    
    int n,nxt[N],len;
    char s[N];
    ll cur,ans[N];
    
    void getnext()
    {
        int j = 0;
        rep(i,2,len)
        {
        while(j && s[j+1] != s[i]) j = nxt[j];
        if(s[j+1] == s[i]) j++;
        nxt[i] = j,ans[i] = ans[j] + 1;
        }
    }
    
    void clear()
    {
        memset(nxt,0,sizeof(nxt));
        memset(ans,0,sizeof(ans));
        cur = 1;
    }
    
    int main()
    {
        n = read();
        while(n--)
        {
        clear();
        scanf("%s",s+1),len = strlen(s+1);
        ans[1] = 1,getnext();
        int j = 0;
        //rep(i,0,len-1) printf("%d ",nxt[i]);enter;
        //rep(i,0,len-1) printf("%lld ",ans[i]);enter;
        rep(i,2,len)
        {
            while(j && s[i] != s[j+1]) j = nxt[j];
            if(s[j+1] == s[i]) j++;
            while(j << 1 > i) j = nxt[j];
            //  printf("!%d
    ",j);
            cur *= (ans[j] + 1),cur %= mod;
        }
        printf("%lld
    ",cur);
        }
        return 0;
    }
  • 相关阅读:
    Beta冲刺置顶随笔
    Beta总结
    用户试用与调查报告
    Beta冲刺第七天
    Beta冲刺第六天
    Beta冲刺第五天
    Beta冲刺第四天
    Beta冲刺第三天
    Beta冲刺第二天
    爬虫基本操作
  • 原文地址:https://www.cnblogs.com/captain1/p/9770007.html
Copyright © 2011-2022 走看看