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\n",ans);
    }
    return 0;
}
相關文章
相關標籤/搜索