CF GYM 102956B

题目概述:

询问有多少个长度为 \(n\),值域在 \([1,m]\) 内的序列满足对于 \(\forall i \in[1,n-1]\) 不存在 \(\max(a_1...a_i)=\min(a_{i+1}...a_n)\)

数据范围:

\(n \leq 400,m\leq 10^9\),模数是质数

题解:

考虑 \(\text{DP}\)。 观察到 \(m\) 很大,那么显然不能把 \(m\) 直接扔进状态,所以考虑计算出 \(g_{k}\) 表示恰好有 \(k\) 个不同值的序列,就可以乘一个组合数算出答案了。但 \(g\) 数组也不能直接计算,那试试二项式反演。设 \(f_{i,k}\) 表示长度为 \(i\) ,值域在 \([1,k]\) 内有多少种合法序列 (换句话说,出现了最多 \(k\) 种不同的值)

\(f_{i,k}\) 可以通过容斥,枚举最后一个不合法的位置在哪里快速计算出来,式子长成

\[f_{i,k}=k^i-\sum_{j=1}^{i-1}\sum_{h=1}^{k}(h_j-(h-1)^j)(f_{i-j,k-h+1}-f_{i-j,k-h}) \]

直接计算,复杂度 \(O(n^4)\) ,考虑前缀和优化,即把式子后面拆成

\[\sum_{j=1}^{i-1}\sum_{h=1}^{k}h^jf_{i-j,k-h+1}+(h-1)^jf_{i-j,k-h}-h^jf_{i-j,k-h}-(h-1)^jf_{i-j,k-h+1} \]

分成四部分分别前缀和优化即可。最后二项式反演一下就可以直接算答案了。

\[g_i=f_i-\sum_{k=1}^{i-1}\binom{i}{k}g_k \]

如果有什么拆的更少做法欢迎教导我。

const int N=405;
int n,m,mod;
int f[N][N],g[N],pw[N][N],sa[2][N][N],sb[2][N][N],sc[2][N][N],sd[2][N][N];
int fac[N],ifac[N];
int add(int x,int y){
	if(x+y>=mod)return x+y-mod;
	return x+y;
}
int del(int x,int y){
	if(x-y<0)return x-y+mod;
	return x-y;
}
int ksm(int x,int k){
	int base=1;
	while(k){
		if(k&1)base=1ll*base*x%mod;
		x=1ll*x*x%mod;k>>=1;
	}
	return base;
}
int C(int n,int m){
	if(n<m)return 0;
	return 1ll*fac[n]*ifac[m]%mod*ifac[n-m]%mod;
}
int main(){
	#ifdef newbiewzs
	//	freopen("data.in","r",stdin);
	#else
	#endif
	n=read();m=read();mod=read();
	for(int i=1;i<=n;i++){
		pw[i][0]=1;
		for(int k=1;k<=n;k++)pw[i][k]=1ll*pw[i][k-1]*i%mod;
	}
	fac[0]=ifac[0]=1;
	for(int i=1;i<=n;i++)fac[i]=1ll*fac[i-1]*i%mod;
	ifac[n]=ksm(fac[n],mod-2);
	for(int i=n-1;i>=1;i--)ifac[i]=1ll*ifac[i+1]*(i+1)%mod;
	for(int i=1;i<=n;i++){
		for(int k=1;k<=n;k++){
			for(int h=1;h<=k;h++){
				f[i][k]=add(f[i][k],sb[(i-1)&1][k][h]);
				f[i][k]=add(f[i][k],sc[(i-1)&1][k][h]);
				f[i][k]=del(f[i][k],sa[(i-1)&1][k][h]);
				f[i][k]=del(f[i][k],sd[(i-1)&1][k][h]);
			}
			f[i][k]=del(pw[k][i],f[i][k]);
			for(int h=1;h<=k;h++){
				sa[i&1][k][h]=add(1ll*sa[(i-1)&1][k][h]*h%mod,1ll*f[i][k-h]*h%mod);
				sb[i&1][k][h]=add(1ll*sb[(i-1)&1][k][h]*h%mod,1ll*f[i][k-h+1]*h%mod);
				sc[i&1][k][h]=add(1ll*sc[(i-1)&1][k][h]*(h-1)%mod,1ll*f[i][k-h]*(h-1)%mod);
				sd[i&1][k][h]=add(1ll*sd[(i-1)&1][k][h]*(h-1)%mod,1ll*f[i][k-h+1]*(h-1)%mod);
			}
		}
	}
	for(int i=1;i<=n;i++){
		g[i]=f[n][i];
		for(int k=1;k<i;k++){
			g[i]=del(g[i],1ll*C(i,k)*g[k]%mod);
		}
	}
	int ans=0;
	for(int i=1;i<=n;i++){
		if(i>m)break;
		int fz=1;
		for(int k=m;k>=m-i+1;k--)fz=1ll*fz*k%mod;
		int tmp=1ll*fz*ifac[i]%mod;
		ans=add(ans,1ll*tmp*g[i]%mod);
	}
	cout<<ans;
	return 0;
}
posted @ 2021-10-07 16:29  newbiewzs  阅读(76)  评论(0)    收藏  举报