G - Ban Permutation

G - Ban Permutation

求长为 \(N(N\leq 100)\) 且满足以下条件的排列 \(P=(P_1,P_2,...,P_N)\) 的个数:

\(\forall 1\leq i\leq N\)\(|P_i-i|\geq X(X\leq 5)\)

  • 考虑使用容斥
  • \(f[i][j][s]\)表示填到第i个数,确定了j个不合法的位置(只填不合法的),并且\([i-(x-1),i+(x-1)]\)的状态为s,那么这个状态乘上\((n-j)!\)就是至少有j个不合法的方案
  • 为什么不在dp的时候确定剩下的位置,原因是我们让一个数填合法的位置有很多,并且会让我们的状态s无法维护。
  • 而限制它只能填不合法的位置则保证位置i-1不会填到i+(x-1)这个位置,保证了转移的正确性
#include<bits/stdc++.h>
#define fo(i,a,b) for (ll (i)=(a);(i)<=(b);(i)++)
#define fd(i,b,a) for (ll (i)=(b);(i)>=(a);(i)--)
#define eb emplace_back
#define mk(x,y) make_pair((x),(y))
#define A puts("YES")
#define B puts("NO")
#define lc (o<<1)
#define rc ((o<<1)|1)
#define pi pair<ll,ll>
using namespace std;
typedef long long ll;
typedef double db;
const int N=105;
const ll P=131;
const ll Q=13331;
const ll inf=1ll<<60;
const ll mo1=1e9+7;
const ll mo2=1e9+9;
const ll mo=998244353;
ll f[N][N][1<<10],n,x,fac[N];
void add(ll &x,ll y){
	x=(x+y)%mo;
}
int main(){
//	freopen("data.in","r",stdin);
	
	fac[0]=1;
	fo(i,1,N-1) fac[i]=fac[i-1]*i%mo;
	
	scanf("%lld %lld",&n,&x);
	f[0][0][0]=1;
	int st=(1<<(2*x-1))-1;
	
	fo(i,0,n-1) fo(j,0,i) fo(k,0,(1<<(2*x-1))-1)  {
		if (!f[i][j][k]) continue;
		add(f[i+1][j][k/2],f[i][j][k]);
		fo(p,-(x-1),x-1) {
			if (i+1+p>0 && i+1+p<=n) {
				if ( !((k/2)&(1<<(p+(x-1)))) ) {
					add(f[i+1][j+1][(k/2)|(1<<(p+(x-1)))], f[i][j][k]);
//					printf("%d\n",(k/2)|(1<<(p+(x-1))));
				}
			}
		}
	}
	
	ll ans=0;
   	fo(i,0,n) {
		fo(k,0,st) {
			if (i&1) add(ans, -f[n][i][k]*fac[n-i]%mo);
			else add(ans, f[n][i][k]*fac[n-i]%mo);
		}
	}
//	printf("%lld\n",ans);
	ans=(ans%mo+mo)%mo;
	printf("%lld",ans);
	
	
	return 0;
}

posted @ 2024-08-24 17:06  gan_coder  阅读(15)  评论(0)    收藏  举报