G - Ban Permutation

gan_coder發表於2024-08-24

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;
}

相關文章