ABC309G Ban Permutation

ABC309G Ban Permutation

求有多少个 \(1\)\(n\) 的排列 \(P\),满足对于任意 \(i\) 都有 \(|i-p_i|\ge X\)
\(1\le n\le 100\)\(1\le X\le 5\)

首先不难将题意转化成车的放置问题:

有一个 \(n\times n\) 的棋盘,要求放置 \(n\) 个互不攻击的车,对于第 \(i\) 行第 \(j\) 列,如果 \(|i-j|<X\),就不能放置车,求方案数。


由于 \(X\) 很小,\(|i-j|<X\) 这个条件就是非常好的,所以可以考虑容斥。

\(f_{i,j}\) 表示,我们考虑了前 \(i\) 行,至少放置 \(j\) 辆不合法的车的方案数。注意这里我们只计算不合法的车的方案数。那么显然答案为 \(\sum_{i=0}^{n}(-1)^if_{n,i}\)

那么第 \(i\) 行的放置就有两种可能,不合法与合法。

如果不合法,那么我们就需要枚举不合法的车放置的位置,并且保证这个位置之前没被使用过。

但注意到这个位置的范围随着 \(i\) 的增加始终都是 \([i-X+1,i+X-1]\),所以就可以加入一个状态 \(S\) 表示这些位置的使用情况。

\(S'\)\(i-1\) 行的状态,考虑 \(i-1\to i\) 的过程,\(i-1\) 行所有不合法的状态都要右移,第 \(i-1-X+1\) 个位置变成了合法位置不需要考虑,所以第 \(i\) 行的状态 \(S\) 即为 \(S'\) 右移一位的答案。

那么枚举这一行放置的不合法的位置 \(p\) 并保证 \(p\) 不在 \(S\) 中,令 \(T\)\(S\) 加入 \(p\) 后的结果,那么显然 \(f_{i,j,T}=f_{i-1,j-1,S}\)

而对于合法情况,直接继承过来第 \(i-1\) 行的答案即可,\(f_{i,j,S}=f_{i-1,j-1,S'}\)

时间复杂度 \(O(n^24^XX)\)

const int MAXN(110);
const int M(1024);

int n,x,m;
int fac[MAXN],f[MAXN][MAXN][M];

int main()
{
	n=read(),x=read(),m=1<<(2*x-1);
	fac[0]=1;
	rep(i,1,n) fac[i]=mul(fac[i-1],i);
	f[0][0][0]=1;
	rep(i,1,n) rep(j,0,i-1) rep(S,0,m-1) 
	{
		int T=S>>1;
		f[i][j][T]=add(f[i][j][T],f[i-1][j][S]);
		rep(k,0,2*x-2) if((!(T&(1<<k)))&&i+k+1-x>=1&&i+k+1-x<=n)
			f[i][j+1][T|(1<<k)]=add(f[i][j+1][T|(1<<k)],f[i-1][j][S]);
	}
	int ans=0;
	rep(i,0,n) rep(S,0,m-1)
	{
		int k=(i&1)?MOD-f[n][i][S]:f[n][i][S];
		ans=add(ans,mul(k,fac[n-i]));
	}
	printf("%d\n",ans);
	return 0;
}
posted @ 2023-07-12 14:46  UperFicial  阅读(29)  评论(0编辑  收藏  举报