题意描述


核心:
总感受题目描述有问题,把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;
}