[atARC118E]Avoid Permutations

为了方便,记$S=\{(i,j)\mid 1\le i,j\le n\}$和$S_{all}=\{(i,j)\mid 0\le i,j\le n+1\}$

令$a_{i}$为给定的序列,其中$a_{i}=-1$的位置表示不限制该位置的值

对于排列$p$,用集合$\{(i,p_{i})\}$来描述其,以下称集合$P$为合法排列集合,当且仅当$P_{0}\subseteq P\subseteq S$、$|P|=n$且$P$中不存在两个坐标同行或同列

($P_{0}$为初始确定的障碍所构成的集合,即$P_{0}=\{(i,a_{i})\mid a_{i}\ge 1\}$)

对于一条路径,用其经过的坐标所构成的集合描述其,以下称集合$X$为合法路径集合,当且仅当$X\subseteq S_{all}$且将$X$中所有元素从上到下、从左到右排序后,第一个元素为$(0,0)$、最后一个元素为$(n+1,n+1)$且相邻两个元素曼哈顿距离为1

不难发现,问题即统计$\sum_{P为合法排列集合}\sum_{X为合法路径集合}[P\cap X=\empty]$

注意到$[P\cap X=\empty]=\sum_{P'\subseteq P\cap X}(-1)^{|P'|}$,代入即$\sum_{P为合法排列集合}\sum_{X为合法路径集合}\sum_{P'\subseteq P\cap X}(-1)^{|P'|}$

交换枚举顺序,即$\sum_{X为合法路径集合}\sum_{P'\subseteq X}(-1)^{|P'|}\sum_{P为合法排列集合,P'\subseteq P}1$

当$P'$满足$P'\subseteq S$且$P'\cup P_{0}$中不存在两个坐标同行或同列,此时最后$P$的方案数即$(n-|P'\cup P_{0}|)!$

下面,对$(X,P')$进行dp,即令$f_{i,j,k,p}$表示当前走到$(i,j)$,当前$|P'\cup P_{0}|=k$且$|P'\cup P_{0}|$在第$i$行和第$j$列是否存在元素($p\in [0,3]$)的贡献和(每一对$(X,P')$的贡献为$(-1)^{|P'|}$)

(为了方便,关于$p$作如下定义:第$i$行存在元素当且仅当$p\and 1=1$,第$j$列存在元素当且仅当$p\and 2=2$)

考虑转移,即枚举$X$的下一个元素是$(i,j+1)$还是$(i+1,j)$,以及其是否要加入$P'$,具体即——
$$
f_{i,j,k,p}->f_{i+1,j,k,p\and 2},f_{i,j+1,k,p\and 1}\\-f_{i,j,k,p}->f_{i+1,j,k+[a_{i+1}\ne j],3}(p\and 2=0且(i+1,j)\in S且(a_{i+1}=j或a_{i+1}=-1且\forall 1\le i\le n,a_{i}\ne j))\\
-f_{i,j,k,p}->f_{i,j+1,k+[a_{i}\ne j+1],3}(p\and 1=0且(i,j+1)\in S且(a_{i}=j+1或a_{i}=-1且\forall 1\le i\le n,a_{i}\ne j+1))
$$
($xf_{S_{1}}->f_{S_{2}}$表示令$f_{S_{2}}+=xf_{S_{1}}$)

初始状态为$f_{0,0,\sum_{i=1}^{n}[a_{i}\ge 1],0}=1$,答案为$\sum_{0\le i\le n}(n-i)!f_{n+1,n+1,i,0}$

时间复杂度为$o(n^{3})$,可以通过

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 205
 4 #define mod 998244353
 5 int n,ans,fac[N],a[N],vis[N],f[N][N][N][4];
 6 int main(){
 7     fac[0]=1;
 8     for(int i=1;i<N;i++)fac[i]=1LL*i*fac[i-1]%mod;
 9     scanf("%d",&n);
10     for(int i=1;i<=n;i++){
11         scanf("%d",&a[i]);
12         if (a[i]>0){
13             vis[0]++;
14             vis[a[i]]=1;
15         }
16     }
17     f[0][0][vis[0]][0]=1;
18     for(int i=0;i<=n+1;i++)
19         for(int j=0;j<=n+1;j++)
20             for(int k=0;k<=n;k++)
21                 for(int p=0;p<4;p++){
22                     if (i<=n){
23                         f[i+1][j][k][p&2]=(f[i+1][j][k][p&2]+f[i][j][k][p])%mod;
24                         if ((!(p&2))&&(i<n)&&(j>=1)&&(j<=n)&&((a[i+1]==j)||(a[i+1]==-1)&&(!vis[j])))f[i+1][j][k+(a[i+1]!=j)][3]=(f[i+1][j][k+(a[i+1]!=j)][3]+mod-f[i][j][k][p])%mod;
25                     }
26                     if (j<=n){
27                         f[i][j+1][k][p&1]=(f[i][j+1][k][p&1]+f[i][j][k][p])%mod;
28                         if ((!(p&1))&&(j<n)&&(i>=1)&&(i<=n)&&((a[i]==j+1)||(a[i]==-1)&&(!vis[j+1])))f[i][j+1][k+(a[i]!=j+1)][3]=(f[i][j+1][k+(a[i]!=j+1)][3]+mod-f[i][j][k][p])%mod;
29                     }
30                 }
31     for(int i=0;i<=n;i++)ans=(ans+1LL*fac[n-i]*f[n+1][n+1][i][0])%mod;
32     printf("%d",ans);
33 }
View Code

 

posted @ 2021-05-18 14:02  PYWBKTDA  阅读(149)  评论(0编辑  收藏  举报