題意描述
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
核心:
總感受題目描述有問題,把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;
}