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

    P2375 [NOI2014]动物园

    为什么复制题目连字体大小一块复制过来了(雾)

    我竟然会做NOI的题目辣~(≧▽≦)/~(看的题解

    总而言之,这是一道简单的KMP问题。题面简直是给没学过KMP的人看的(比如我)。

    我们发现,这个所谓的num数组和nxt有异曲同工之妙。但是我们对于不能重合这一块有一点问号。那我们先不管重不重合,先给他记录成重合的。

    于是在标记nxt时同时也可以把num标记。原理是,nxt记录的是该字符串相同的前缀字符个数,num[i]记录的是当前字符作为从0到i的子串内后缀与前缀相同的子串的子串的数目。我们发现,其实他就是num[j]+1,j就是nxt[i]!可以举几个例子模拟一下。

    这样一来查询的时候也很方便了。

    问题来了,怎么去重呢?如果j已经到i<<1的时候,我们将j挪到nxt[j]就好了,直到j<i/2。因为上面我们记录的num数组的特性,如果有重叠此时的值就相当于在nxt[j]的时候的没有重叠的串的num数。模拟一下也很好理解的。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #define mod 1000000007 
    using namespace std;
    typedef long long ll;
    const int maxn=1e6+5;
    char a[maxn];
    int nxt[maxn],len,num[maxn];
    inline void getnxt()
    {
        int k=-1,j=0;
        nxt[0]=-1;
        while(j<len)
        {
            if(k==-1 or a[j]==a[k])nxt[++j]=++k,num[j]=num[k]+1;
            else k=nxt[k];
        }
    }
    inline void kmp()
    {
        int j=0,i=1;
        ll ans=1;
        while(i<len)
        {
            if(j==-1 or a[j]==a[i]){
                j++,i++;
                while((j<<1)>=(i+1))j=nxt[j];
                ans=(ans*(ll)(num[j]+1))%mod;
            }
            else j=nxt[j];
        }
        printf("%lld
    ",ans);
    }
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%s",&a);
            len=strlen(a);
            memset(nxt,0,sizeof nxt);
            num[0]=0,num[1]=1;
            getnxt();
            kmp();
        }
        return 0;
    }
  • 相关阅读:
    python3数据库配置,远程连接mysql服务器
    Ubuntu 16.04安装JDK
    用Python从零开始创建区块链
    理解奇异值分解SVD和潜在语义索引LSI(Latent Semantic Indexing)
    gensim介绍(翻译)
    记一次浅拷贝的错误
    Heap queue algorithm
    Python
    python列表中插入字符串使用+号
    Linux(Ubuntu)使用 sudo apt-get install 命令安装软件的目录在哪?
  • 原文地址:https://www.cnblogs.com/BrotherHood/p/13142031.html
Copyright © 2011-2022 走看看