解法
考慮如果A中的兩個相鄰位置都確定了的話,這兩個位置所對應的B的位置不會對B的方案產生影響,直接不管就可以了。
如果建立圖論模型,可以發現B的每一個數相當於對A中的兩個數匹配後,較小的值
然後記錄每個數是否在A中出現過,然後可以從大到小dp:
表示考慮了的所有位置,其中有個已經在A中出現的還需要向比i更小的位置匹配,有個沒有在A中出現的需要向比i更小的位置匹配。
轉移考慮從轉移過來:
#include<bits/stdc++.h>
using namespace std;
const int maxn=605;
const int mod=1e9+7;
inline int read(){
char c=getchar();int t=0,f=1;
while((!isdigit(c))&&(c!=EOF)){if(c=='-')f=-1;c=getchar();}
while((isdigit(c))&&(c!=EOF)){t=(t<<3)+(t<<1)+(c^48);c=getchar();}
return t*f;
}
int n,a[maxn],b[maxn],t,c[maxn];
int f[2][maxn][maxn];
inline void add(int &a,int b){
a=a+b;
if(a>=mod)a=a-mod;
if(a<0)a=a+mod;
}
signed main(){
n=read();
for(int i=1;i<=2*n;i++)a[i]=read();
int cnt=0;
for(int i=1;i<=2*n;i+=2){
if((a[i]!=-1)&&(a[i+1]!=-1))b[a[i]]=b[a[i+1]]=2;
else if(a[i]!=-1){b[a[i]]=1;}
else if(a[i+1]!=-1){b[a[i+1]]=1;}
else cnt++;
}
for(int i=1;i<=2*n;i++){
if(b[i]==1)c[++t]=1;
else if(b[i]==0)c[++t]=2;
}
f[t&1][0][0]=1;
for(int i=t;i>=1;i--){
memset(f[(i-1)&1],0,sizeof(f[(i-1)&1]));
for(int j=0;j<=t&&j<=n;j++){
for(int k=0;k<=t&&k<=n;k++){
if(c[i]==1){
add(f[(i-1)&1][j+1][k],f[i&1][j][k]);
if(k)add(f[(i-1)&1][j][k-1],f[i&1][j][k]);
}
else{
add(f[(i-1)&1][j][k+1],f[i&1][j][k]);
if(k)add(f[(i-1)&1][j][k-1],f[i&1][j][k]);
if(j)add(f[(i-1)&1][j-1][k],(1ll*f[i&1][j][k]*j)%mod);
}
}
}
}
int ans=f[0][0][0];
for(int i=1;i<=cnt;i++)
ans=1ll*ans*i%mod;
printf("%d\n",ans);
return 0;
}