Description
有两个长度为n的排列A和B,定义排列的价值f(A,B)为所有满足A[i]>B[i]的位置i的数量。
现给出n,A,B和S,其中A和B中有一些位置的数未知,问有多少种可能的填数的方案使得f(A,B)=S
对于100%的数据满足,1<=S<=n<=4000
保证不存在一个位置i满足A[i]=0且B[i]=0
Solution
直接做很难做,不妨考虑转化一下
显然上面为0和下面为0的情况是相似的,可以分开考虑,两个都不为0的直接判掉。
下面只讨论上面为0的情况
我们可以把剩下的数拉出来排个序,按顺序选。
设 F[i][j] 表示选定了前i个,造成了j的贡献。
设
r
为第i个比对应的b的多少个大。
转移似乎很显然,
最后
F[m][j]=F[m][j]∗(m−j)!
把这些没造成贡献的排列一下。
但是,这样是错的。
有可能对于某个点没有造成贡献的,选了后面的b,令后面的即使不得不选前面的而造成了额外的贡献。
所以我们改一下状态
设
F[i][j]
表示选定了前i个,至少造成了j的贡献。
这样上面的转移成立。
现在要求刚好为j的答案,可以容斥一下。
可以发现
F[m][k],k>j
在
F[m][j]
中多算了
Cjk
次。
容斥一下即可。
Code
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#include <cstdlib>
#include <set>
#include <map>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define LL long long
#define mo 1000000007
#define N 4005
#define LL long long
using namespace std;
int n,m,a[N],b[N],d[N],s[N];
LL f[N][N],g[N],h[N],js[N],ny[N];
bool bz[N];
LL ksm(LL k,LL n)
{
LL s=1;
for(;n;n>>=1,(k*=k)%=mo) if(n&1) (s*=k)%=mo;
return s;
}
LL zh(LL m,LL n)
{
return js[n]*ny[m]%mo*ny[n-m]%mo;
}
int main()
{
cin>>n>>m;
fo(i,1,n) scanf("%d",&a[i]);
fo(i,1,n) scanf("%d",&b[i]);
js[0]=ny[0]=1;
fo(i,1,n) js[i]=js[i-1]*(LL)i%mo,ny[i]=ksm(js[i],mo-2);
fo(i,1,n)
{
if(a[i]>b[i]&&b[i]!=0) m--;
if(a[i]==0) s[b[i]]++;
if(a[i]!=0) bz[a[i]]=1;
}
fo(i,1,n)
{
if(!bz[i]) d[++d[0]]=i;
s[i]+=s[i-1];
}
f[0][0]=1;
fo(i,1,d[0])
{
fo(j,0,s[d[i]-1])
{
f[i][j]=f[i-1][j];
if(j) (f[i][j]+=f[i-1][j-1]*(LL)(s[d[i]-1]-j+1)%mo)%=mo;
if(i==d[0]) (f[i][j]*=js[d[0]-j])%=mo;
}
}
fo(j,0,s[d[d[0]]-1])
{
g[j]=f[d[0]][j];
LL v=-1;
fo(k,j+1,s[d[d[0]]-1])
{
(g[j]+=v*zh(j,k)*f[d[0]][k]%mo)%=mo;
v=-v;
}
}
d[0]=0;
memset(s,0,sizeof(s));
memset(f,0,sizeof(f));
memset(bz,0,sizeof(bz));
fo(i,1,n)
{
if(b[i]==0) s[a[i]]++;
else bz[b[i]]=1;
}
fod(i,n,1)
{
if(!bz[i]) d[++d[0]]=i;
s[i]+=s[i+1];
}
f[0][0]=1;
fo(i,1,d[0])
{
fo(j,0,s[d[i]+1])
{
f[i][j]=f[i-1][j];
if(j) (f[i][j]+=f[i-1][j-1]*(s[d[i]+1]-j+1)%mo)%=mo;
if(i==d[0]) (f[i][j]*=js[d[0]-j])%=mo;
}
}
fo(j,0,s[d[d[0]]+1])
{
h[j]=f[d[0]][j];
LL v=-1;
fo(k,j+1,s[d[d[0]]+1])
{
(h[j]+=v*zh(j,k)*f[d[0]][k]%mo)%=mo;
v=-v;
}
}
LL ans=0;
fo(j,0,m) (ans+=g[j]*h[m-j]%mo)%=mo;
printf("%lld\n",(ans+mo)%mo);
}