Description
有兩個長度爲n的排列A和B,定義排列的價值f(A,B)爲所有滿足A[i]>B[i]的位置i的數量。
現給出n,A,B和S,其中A和B中有一些位置的數未知,問有多少種可能的填數的方案使得f(A,B)=S
Input
第一行兩個整數n和S
第二行n個數表示排列A
第三行n個數表示排列B
其中A和B中某些位置是0表示當前位置上的數還未確定,保證不存在一個位置i滿足A[i]=0且B[i]=0
Output
一行一個整數表示使得f(A,B)=S的填數的方案數,由於答案可能很大,對10^9+7取模。
Sample Input
4 2
4 2 0 0
0 0 4 2
Sample Output
2
Data Constraint
對於20%的數據滿足,1<=n<=10
對於50%的數據滿足,1<=n<=20
對於70%的數據滿足,1<=n<=200
對於100%的數據滿足,1<=S<=n<=4000
保證不存在一個位置i滿足A[i]=0且B[i]=0
比賽的時候看錯題了,以爲是個水題。。發現以後只會做50分,弱爆了。。
這題與bzoj3198有異曲同工之妙,都是組合數作爲容斥係數。
首先可以發現,上或者下爲0是相同的處理方法,所以這裏只討論a[i]=0,b[i]!=0的情況。
把這些列抽出來,存在u,v裏面,然後進行DP。
可以發現,此時並不需要遵守同下標的要求,任意兩個之間只要大於號成立皆可配對,於是我們使用組合數處理,但是由於會算重,所以進行容斥。
具體來說就是
分成兩個部分處理即可。
那麼最終答案就是
%%%ymw。
#include<cstdio>
#include<algorithm>
#include<cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=4e3+5;
int n,m,a[N],b[N],ans;
int f[N],g[N],a1[N],b1[N];
int dp[N][N],vis[N];
const int mo=1e9+7;
typedef long long ll;
ll fac[N],inv[N];
inline ll pow(ll a,ll b)
{
ll ret=1;
while (b)
{
if (b&1)ret=ret*a%mo;
a=a*a%mo;
b>>=1;
}
return ret;
}
inline int C(int n,int m)
{
return 1ll*fac[n]*inv[m]%mo*inv[n-m]%mo;
}
inline void solve1()
{
memset(vis,0,sizeof(vis));
int tot=0;
fo(i,1,n)vis[a[i]]=1;
fo(i,1,n)if (!vis[i])a1[++tot]=i;
tot=0;
fo(i,1,n)if (!a[i])b1[++tot]=b[i];
sort(b1+1,b1+tot+1);
fo(i,1,tot+1)dp[i][0]=1;
fo(j,1,tot)
{
int x=tot+1;
fd(i,tot,1)
{
dp[i][j]=dp[i+1][j];
while (x>1&&b1[i]<a1[x-1])x--;
if (tot-x+1>j-1)
dp[i][j]=
(dp[i][j]+1ll*dp[i+1][j-1]*(tot-x+1-j+1)%mo)%mo;
}
}
fo(i,0,tot)
{
fo(j,i,tot)
if ((j-i)%2==0)
{
f[i]=(f[i]+1ll*dp[1][j]*C(j,i)%mo*fac[tot-j]%mo)%mo;
}
else
{
f[i]=(f[i]-1ll*dp[1][j]*C(j,i)%mo*fac[tot-j]%mo)%mo;
if(f[i]<0)f[i]+=mo;
}
}
}
inline void solve2()
{
memset(vis,0,sizeof(vis));
int tot=0;
fo(i,1,n)vis[b[i]]=1;
fo(i,1,n)if (!vis[i])b1[++tot]=i;
tot=0;
fo(i,1,n)if (!b[i])a1[++tot]=a[i];
sort(a1+1,a1+tot+1);
memset(dp,0,sizeof(dp));
fo(i,1,tot+1)dp[i][0]=1;
fo(j,1,tot)
{
int x=tot+1;
fd(i,tot,1)
{
dp[i][j]=dp[i+1][j];
while (x>1&&b1[i]<a1[x-1])x--;
if (tot-x+1>j-1)
dp[i][j]=(dp[i][j]+1ll*dp[i+1][j-1]*(tot-x+1-j+1)%mo)%mo;
}
}
fo(i,0,tot)
{
fo(j,i,tot)
if ((j-i)%2==0)
{
g[i]=(g[i]+1ll*dp[1][j]*C(j,i)%mo*fac[tot-j]%mo)%mo;
}
else
{
g[i]=(g[i]-1ll*dp[1][j]*C(j,i)%mo*fac[tot-j]%mo)%mo;
if(f[i]<0)f[i]+=mo;
}
}
}
int main()
{
freopen("arrange.in","r",stdin);
freopen("arrange.out","w",stdout);
scanf("%d%d",&n,&m);
fo(i,1,n)scanf("%d",&a[i]);
fo(i,1,n)scanf("%d",&b[i]);
fac[0]=inv[0]=1;
fo(i,1,n)fac[i]=1ll*fac[i-1]*i%mo,inv[i]=pow(fac[i],mo-2);
solve1();
solve2();
fo(i,1,n)if (a[i]&&b[i]&&a[i]>b[i])m--;
ll ans=0;
fo(i,0,m)ans=(ans+1ll*f[i]*g[m-i]%mo)%mo;
printf("%lld\n",ans%mo);
}