求长为 \(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;
}
标签:const,ll,合法,leq,Permutation,Ban,define
From: https://www.cnblogs.com/ganking/p/18377953