题目
因为直接计算每个符合要求的序列的权值比较困难(要求是或起来的),所以考虑算出所有序列的权值再减去不符合条件的序列权值。
所有序列的权值等于
k
n
−
m
×
(
n
−
m
+
1
)
k^{n-m}\times(n-m+1)
kn−m×(n−m+1)。
考虑后者即不符合条件的序列的权值和怎么计算。
1.
{
a
}
\{a\}
{a} 就是一个符合条件的序列
那么答案为
0
0
0
2.
{
a
}
\{a\}
{a} 中元素不重复
可以注意到,既然
{
a
}
\{a\}
{a} 不重复,那么每个数没有本质区别,所以统计出
{
a
}
\{a\}
{a} 等于任意长度为
m
m
m 的元素不重复的序列时的答案再除以
k
m
‾
k^{\underline m}
km。
设
f
[
i
]
[
j
]
f[i][j]
f[i][j] 表示填了
i
i
i 个数,最后
j
j
j 个数不重复的方案数
f
[
i
]
[
j
]
←
(
k
−
j
+
1
)
×
f
[
i
−
1
]
[
j
−
1
]
f[i][j]\leftarrow (k-j+1)\times f[i-1][j-1]
f[i][j]←(k−j+1)×f[i−1][j−1]
f
[
i
]
[
j
]
←
f
[
i
−
1
]
[
k
]
(
k
≥
j
)
f[i][j]\leftarrow f[i-1][k](k\ge j)
f[i][j]←f[i−1][k](k≥j)
设
g
[
i
]
[
j
]
g[i][j]
g[i][j] 表示填了
i
i
i 个数,最后
j
j
j 个数不重复的序列,其中含有长度为
m
m
m 的元素不重复的子串的个数之和。
g
[
i
]
[
j
]
←
(
k
−
j
+
1
)
×
g
[
i
−
1
]
[
j
−
1
]
g[i][j]\leftarrow (k-j+1)\times g[i-1][j-1]
g[i][j]←(k−j+1)×g[i−1][j−1]
g
[
i
]
[
j
]
←
g
[
i
−
1
]
[
k
]
(
k
≥
j
)
g[i][j]\leftarrow g[i-1][k](k\ge j)
g[i][j]←g[i−1][k](k≥j)
g
[
i
]
[
j
]
+
=
f
[
i
]
[
j
]
(
j
≥
m
)
g[i][j]+=f[i][j](j\ge m)
g[i][j]+=f[i][j](j≥m)
注意在枚举的时候
j
<
k
j<k
j<k 即可保证不存在合法的情况。
答案是
∑
i
=
1
k
−
1
g
[
n
]
[
i
]
k
m
‾
\frac{\sum_{i=1}^{k-1}g[n][i]}{k^{\underline{m}}}
km∑i=1k−1g[n][i]
3.
{
a
}
\{a\}
{a} 中元素有重复
对于原串中出现的每一个
a
a
a 都分开统计答案,换言之,统计
a
a
a 出现
[
i
,
i
+
m
−
1
]
[i,i+m-1]
[i,i+m−1] 区间时填原序列的方案数,答案即为前面每种情况方案数的总和。
记
L
L
L 表示极长前缀长度使得
a
1
,
a
2
,
⋯
,
a
L
a_1,a_2,\cdots,a_L
a1,a2,⋯,aL 互不相同。
R
R
R 表示极长后缀长度使得
a
m
−
R
+
1
,
⋯
,
a
m
a_{m-R+1},\cdots,a_m
am−R+1,⋯,am 互不相同。
f
[
0
]
[
L
]
=
1
f[0][L]=1
f[0][L]=1
g
[
0
]
[
R
]
=
1
g[0][R]=1
g[0][R]=1
然后
f
f
f 和
g
g
g 都做一遍与前面第二种情况中
f
f
f 相同的转移就可以了。
答案是
∑
i
=
1
n
−
m
+
1
(
∑
j
=
1
k
−
1
f
[
i
−
1
]
[
j
]
)
×
(
∑
j
=
1
k
−
1
g
[
i
−
1
]
[
j
]
)
\sum_{i=1}^{n-m+1} (\sum_{j=1}^{k-1}f[i-1][j])\times(\sum_{j=1}^{k-1}g[i-1][j])
∑i=1n−m+1(∑j=1k−1f[i−1][j])×(∑j=1k−1g[i−1][j])。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<map>
#include<queue>
using namespace std;
const int N=25005;
const int M=405;
const int mod=1e9+7;
int n,k,m;
int a[N],inv[N],cnt[N],f[N][M],g[N][M],suf[N][M],suf1[N][M],suf2[N][M];
bool vis1[N],vis2[N];
inline int read()
{
int s=0,t=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')t=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+(ch^48),ch=getchar();
return s*t;
}
inline int ksm(int a,int b)
{
int res=1;
while(b)
{
if(b&1) res=1ll*res*a%mod;
a=1ll*a*a%mod;
b>>=1;
}
return res;
}
inline bool check()
{
for(int i=1;i<=m;++i) ++cnt[a[i]];
for(int i=1;i<=m;++i)
if(cnt[a[i]]>1) return false;
return true;
}
inline int calc1()
{
if(m>=k) return 0;
f[0][0]=1;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=k-1;++j)
{
f[i][j]=(f[i][j]+suf[i-1][j])%mod;
f[i][j]=(f[i][j]+1ll*f[i-1][j-1]*(k-j+1)%mod)%mod;
}
for(int j=k-1;j;--j) suf[i][j]=(suf[i][j+1]+f[i][j])%mod;
}
memset(suf,0,sizeof(suf));
for(int i=1;i<=n;++i)
{
for(int j=1;j<=k-1;++j)
{
g[i][j]=(g[i][j]+suf[i-1][j])%mod;
g[i][j]=(g[i][j]+1ll*g[i-1][j-1]*(k-j+1)%mod)%mod;
if(j>=m) g[i][j]=(g[i][j]+f[i][j])%mod;
}
for(int j=k-1;j;--j) suf[i][j]=(suf[i][j+1]+g[i][j])%mod;
}
int qwq=1;
for(int i=1;i<=m;++i) qwq=1ll*qwq*inv[k-i+1]%mod;
return 1ll*suf[n][1]*qwq%mod;
}
inline int calc2()
{
int l=0,r=0;
while(!vis1[a[l+1]]){++l;vis1[a[l]]=1;}
while(!vis2[a[m-r]]){vis2[a[m-r]]=1,++r;}
if(l>=k||r>=k) return 0;
bool ok=0;
memset(cnt,0,sizeof(cnt));
for(int i=1;i+k-1<=m;++i)
{
bool qwq=0;
for(int j=i;j<=i+k-1;++j) ++cnt[a[j]];
for(int j=i;j<=i+k-1;++j)
if(cnt[a[j]]>1) qwq=1;
for(int j=i;j<=i+k-1;++j) --cnt[a[j]];
ok|=(qwq==0);
}
if(ok) return 0;
f[0][l]=suf1[0][l]=1;
g[0][r]=suf2[0][r]=1;
for(int j=k-1;j;--j)
{
suf1[0][j]=(suf1[0][j+1]+suf1[0][j])%mod;
suf2[0][j]=(suf2[0][j+1]+suf2[0][j])%mod;
}
for(int i=1;i<=n;++i)
{
for(int j=1;j<=k-1;++j)
{
f[i][j]=(f[i][j]+1ll*(k-j+1)*f[i-1][j-1]%mod)%mod;
f[i][j]=(f[i][j]+suf1[i-1][j])%mod;
g[i][j]=(g[i][j]+1ll*(k-j+1)*g[i-1][j-1]%mod)%mod;
g[i][j]=(g[i][j]+suf2[i-1][j])%mod;
}
for(int j=k-1;j;--j)
{
suf1[i][j]=(suf1[i][j+1]+f[i][j])%mod;
suf2[i][j]=(suf2[i][j+1]+g[i][j])%mod;
}
}
int qwq=0;
for(int i=1;i+m-1<=n;++i) qwq=(qwq+1ll*suf1[i-1][1]*suf2[n-m-i+1][1]%mod)%mod;
return qwq;
}
// f[i][j] 填了前 i 个数,最后 j 个数不重复 的方案数
// g[i][j] 填了前 i 个数,最后 j 个数不重复,长度为 m
int main()
{
n=read();
k=read();
m=read();
for(int i=1;i<=m;++i) a[i]=read();
inv[0]=inv[1]=1;
for(int i=2;i<=k;++i) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
int res=1ll*ksm(k,n-m)*(n-m+1)%mod;
if(check()) printf("%d",(res-calc1()+mod)%mod);
else printf("%d",(res-calc2()+mod)%mod);
return 0;
}
404

被折叠的 条评论
为什么被折叠?



