zoukankan      html  css  js  c++  java
  • 2019牛客国庆集训派对day1-Distinct Substrings(扩展KMP)

    题意描述

    核心:

    总感觉题目描述有问题,把s1看出是字符, s1...sn组成一个字符串,h(s,c)表示字符s末尾添加一个字符c的时候,字串的数目;
    增加的字串可以看成是以字符C结尾的后缀;s1..sn颠倒之后看出字符串(sn..s1)T串,对于CT串,我们求出CT与T各个位置的最大公共前缀,就得出了共有的字串部分;这个我们可以借助扩展kmp来求,nxt[i]表示T[i-(n-1)]与T之间公告前缀部分,求CT与T[i]的公共前缀,若T[i]为字符C, 则CT[i+1]与CT公共前缀是nxt[i+1] 
    

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    #define mod 1000000007
    const int N=1e6+7;
    int x[N],w[N],nxt[N];
    int n,m;
    void pre_exkmp()
    {
        nxt[0]=n;
        int j=0;
        while(j+1<n&&x[j]==x[j+1])j++;
        nxt[1]=j;  // 从一开始,nxt[i-k]确实要前进
        int k=1;
        for(int i=2;i<n;i++)
        {
            int p=nxt[k]+k,t=nxt[i-k];
            if(i+t<p)nxt[i]=t;
            else 
            {
                j=p-i<0?0:p-i;
                while(i+j<n&&x[i+j]==x[j])j++;
                nxt[i]=j;k=i;
            }
        }
    }
    int main()
    {
        while(~scanf("%d%d",&n,&m)) {
            for (int i=0;i<n;i++) scanf("%d",&x[n-i-1]);
            pre_exkmp();
            nxt[n]=0;
            for (int i=1;i<=m;i++) w[i]=-1; // 没有C字符,长度增加n+1
            // memset 在牛客是超时的啊
            for(int i=0;i<=n-1;++i) w[x[i]]=max(nxt[i+1],w[x[i]]);
            int ans=0,p=1;
            for(int i=1;i<=m;++i)
            {
                p=1ll*p*3%mod;
                ans^=1ll*p*(n-w[i])%mod;
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    
    
  • 相关阅读:
    静下来好好学习
    深入学习Redis主从复制
    深入学习Redis持久化
    TPS、并发用户数、吞吐量关系
    P1067 多项式输出
    P1014 Cantor表
    P2089 烤鸡
    P1579 哥德巴赫猜想(升级版)
    P1217 [USACO1.5]回文质数 Prime Palindromes
    校内比赛 城市交通费
  • 原文地址:https://www.cnblogs.com/xidian-mao/p/11670070.html
Copyright © 2011-2022 走看看