ARC100F题解

写一篇自己能看得懂的题解。。。。。。

先考虑一个正难则反,用 \(a\) 序列出现过的次数减去在不好的序列里面的出现次数。

前者显然是 \(k^{n-m}(n-m+1)\),考虑后者的答案。

分三种情况讨论:

  1. \(a\) 是一个好序列

显然为 \(0\)

  1. \(a\) 中的数字互不相同

此时存在 \(m<k\)

考虑一个 DP,设 \(f[n][j]\) 表示长度为 \(n\) 的不好的序列中,最后 \(j\) 个数字互不同但最后 \(j+1\) 个数字中存在相同的数。

转移比较明显,是 \(f[n][j]=f[n-1][j-1]\times(n-j)+\sum_{i=j}^{k}f[n-1][i]\)

然后设 \(g[n][j]\) 表示长度为 \(n\) 的不好的序列中,最后 \(j\) 个数字互不相同但最后 \(j+1\) 个数字中存在相同的数的序列中 \(a\) 的出现次数。

转移和 \(f\) 是一样的,但是需要注意当 \(j\geq m\) 的时候后缀中一定包含一个 \(a\),需要令 \(g[n][j]\) 加上 \(f[n][j]\)

需要注意 \(a\) 序列只有一种,但是 \(g\) 把所有 \(a\) 的排列也都包含了,需要除以 \(k^{\underline m}\) 才行。

  1. \(a\) 中存在相同的数字

枚举 \(a\) 在序列中出现的位置,求出 \(a\) 序列的一个最长的前缀 \(Q\) 和最长的后缀 \(P\) 满足 \(Q\)\(P\) 中的数互不相同,限制相当于变为强制加上这个前缀之后不存在相邻的。

DP 和上述的 \(f\) 是相同的,但是初始值变成了 \(f[0][|Q|]=1\)

复杂度均为 \(O(nk)\)

#include<cstdio>
const int M=25005,N=405,mod=1e9+7;
int n,m,k,q,p,A[M],f[M][N],g[M][N];bool vis[N];
inline int pow(int a,int b=mod-2){
	int ans(1);for(;b;b>>=1,a=1ll*a*a%mod)if(b&1)ans=1ll*ans*a%mod;return ans;
}
inline bool check(){
	for(int i=1;i+k-1<=m;++i){
		for(int j=1;j<=k;++j)vis[j]=false;for(int j=i;j<=i+k-1;++j)if(vis[A[j]])goto end;else vis[A[j]]=true;
		return true;end:;
	}
	return false;
}
inline void calc(int(*f)[N]){
	for(int i=1;i<=n;++i){
		for(int j=1;j<k;++j)f[i][j]=(1ll*(mod+f[i-1][j-1]-f[i-1][j])*(k-j+1)+f[i-1][j])%mod;
		for(int j=k-1;j>=0;--j)f[i][j]=(f[i][j]+f[i][j+1])%mod;
	}
}
signed main(){
	int ans(1);scanf("%d%d%d",&n,&k,&m);for(int i=1;i<=m;++i)scanf("%d",A+i);
	for(int i=1;i<=n-m;++i)ans=1ll*ans*k%mod;ans=1ll*ans*(n-m+1)%mod;
	if(check())return printf("%d",ans),0;q=m;p=1;
	for(int j=1;j<=k;++j)vis[j]=false;for(int i=1;i<=m;++i)if(vis[A[i]]){q=i-1;break;}else vis[A[i]]=true;
	for(int j=1;j<=k;++j)vis[j]=false;for(int i=m;i>=1;--i)if(vis[A[i]]){p=m-i;break;}else vis[A[i]]=true;
	if(q==m&&p==1){
		f[0][0]=1;
		for(int i=1;i<=n;++i){
			for(int j=1;j<k;++j){
				f[i][j]=(1ll*(mod+f[i-1][j-1]-f[i-1][j])*(k-j+1)+f[i-1][j])%mod;
				g[i][j]=(1ll*(mod+g[i-1][j-1]-g[i-1][j])*(k-j+1)+g[i-1][j])%mod;
				if(j>=m)g[i][j]=(g[i][j]+f[i][j])%mod;
			}
			for(int j=k-1;j>=0;--j)f[i][j]=(f[i][j]+f[i][j+1])%mod,g[i][j]=(g[i][j]+g[i][j+1])%mod;
		}
		int ret(g[n][0]);for(int i=k;i>k-m;--i)ret=1ll*ret*pow(i)%mod;printf("%d",(ans-ret+mod)%mod);
	}
	else{
		for(int i=0;i<=q;++i)f[0][i]=1;for(int i=0;i<=p;++i)g[0][i]=1;calc(f);calc(g);
		int ret(0);for(int i=0;i<=n-m;++i)ret=(ret+1ll*f[i][0]*g[n-m-i][0])%mod;printf("%d",(ans-ret+mod)%mod);
	}
}
posted @ 2022-08-20 10:45  Prean  阅读(59)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};