Codeforces 1874F - Jellyfish and OEIS

发布时间 2023-10-03 23:41:08作者: tzc_wk

考虑对 \(\sum m_i-i+1\) 个不可行的集合进行容斥,即钦定一些区间集,要求它们对应的 \(p_l,p_{l+1},\cdots,p_r\) 必须是 \([l,r]\) 的排列,计算方案数乘以容斥系数之和。

如果容斥的集合中存在相交的区间,那么这个方案数其实不太好计算。不过根据区间的性质,对于 \(l_1<l_2\le r_1<r_2\),如果 \(p[l_1...r_1],[l_2...r_2]\) 都分别是 \([l_1,r_1],[l_2,r_2]\) 的排列,那么 \(p[l_1...l_2-1],p[r_1+1...r_2]\) 也分别是 \([l_1,l_2-1],[r_1+1,r_2]\) 的排列。这样感性理解,如果存在严格相交的区间,那么容斥系数可以抵消,具体证明可以构造个双射,这里略去。

这样我们只用考虑容斥的区间只有不交和包含的情况。这样区间构成了一个树形结构,并且方案数是好算的——就是每一层散点个数的阶乘之积。这就很方便我们区间 DP 了。设 \(f_{l,r}\) 表示只考虑包含于 \([l,r]\) 的区间,且 \([l,r]\) 被容斥的所有方案的容斥系数乘以方案数之和。\(g_{l,r,x}\) 表示只考虑包含于 \([l,r]\) 的区间,这一层有 \(x\) 个散点的所有方案的容斥系数乘以方案数之和。这样复杂度是 \(n^4\) 的,且常数很小,可以通过。

不过话说回来,为啥 \(n^4\)\(200\)?很替 csy 抱不平。

const int MAXN=200;
const int MOD=1e9+7;
int n,lim[MAXN+5],fac[MAXN+5],f[MAXN+5][MAXN+5],g[MAXN+5][MAXN+5][MAXN+5];
int main(){
	scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&lim[i]);
	for(int i=(fac[0]=1);i<=n;i++)fac[i]=1ll*fac[i-1]*i%MOD;
	for(int i=1;i<=n+1;i++)g[i][i-1][0]=1;
	for(int len=1;len<=n;len++)for(int l=1,r=len;r<=n;l++,r++){
		for(int x=1;x<=r-l+1;x++)g[l][r][x]=g[l+1][r][x-1];
		for(int k=l;k<=min(r-1,lim[l]);k++)for(int x=0;x<=r-k;x++)
			g[l][r][x]=(g[l][r][x]+1ll*g[k+1][r][x]*(MOD-f[l][k]))%MOD;
		for(int x=0;x<=r-l+1;x++)f[l][r]=(f[l][r]+1ll*fac[x]*g[l][r][x])%MOD;
		if(r<=lim[l])g[l][r][0]=(g[l][r][0]-f[l][r]+MOD)%MOD;
	}printf("%d\n",(lim[1]==n)?0:f[1][n]);
	return 0;
}