[DP记录]ARC118E Avoid Permutations
command_block · · 个人记录
题意 :
-
对于排列
P_{1\sim n} ,定义f(P) 为:有一个
(n+2)\times (n+2) 的矩阵,行列编号分别为0\sim n+1 。(i,P_i) 为障碍,其余位置无障碍。从
0,0 出发,只能向下向右,不能经过障碍,到达(n+1,n+1) 的方案数。
现在给出一个部分未填的排列
答案对
考虑
使用容斥原理,枚举一个含
为了方便,记
方案数为:
用 DP 求解,记
注意到
#include<algorithm>
#include<cstdio>
#define MaxN 205
using namespace std;
const int mod=998244353;
void add(int &a,int b){a=(a+b)%mod;}
int n,c,a[MaxN],b[MaxN],fac[MaxN],dp[MaxN][MaxN][MaxN][2][2];
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)b[i]=-1;
for (int i=1;i<=n;i++){
scanf("%d",&a[i]);
if (a[i]!=-1){c++;b[a[i]]=1;}
}
b[0]=b[a[n+1]=n+1]=1;
dp[0][0][0][0][0]=1;
for (int i=0;i<=n+1;i++)
for (int j=0;j<=n+1;j++)if (i+j==0||i+j==n+n+2||a[i]!=j)
for (int k=0;k<=n-c;k++)
for (int e1=0;e1<=1;e1++)
for (int e2=0;e2<=1;e2++){
int now=dp[i][j][k][e1][e2];
if (!now)continue;
if (i<=n){
add(dp[i+1][j][k][e1][0],now);
if (!e1&&a[i+1]==-1&&b[j]==-1)add(dp[i+1][j][k+1][1][1],now);
}
if (j<=n){
add(dp[i][j+1][k][0][e2],now);
if (!e2&&a[i]==-1&&b[j+1]==-1)add(dp[i][j+1][k+1][1][1],now);
}
}
fac[0]=1;for (int i=1;i<=n;i++)fac[i]=1ll*fac[i-1]*i%mod;
int ans=0;
for (int k=0;k<=n-c;k++){
int now=1ll*fac[n-c-k]*dp[n+1][n+1][k][0][0]%mod;
if (k&1)ans=(ans-now+mod)%mod;else ans=(ans+now)%mod;
}printf("%d",ans);
return 0;
}