排列
Description
有两个长度为
n
的排列
现给出
n
,
若第
i
位上位置则为
答案可能很大,对
109
+
7
取模。
Data Constraint
保证不存在一个位置
i
满足
Solution
很显然可以把问题拆成两个完全一样的问题。
把
设
设
fi,j
表示
a
序列中的数做到了第
易得
设
Gi
表示整个
a
序列已处理完,保证有
易得
设
通过容斥原理可得
移项可得
Fi
=
Gi
-
∑j>i
Fj
*
Cij
这样子问题就解决了,最后答案的计算只需合并两个子问题的答案即可。
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,j,l) for(int i=j;i<=l;i++)
#define fd(i,j,l) for(int i=j;i>=l;i--)
using namespace std;
typedef long long ll;
const ll N=45e2,mo=1e9+7;
ll f1[N],g1[N][N],f2[N],g2[N][N],a[N],b[N],c[N],d[N],e[N],least[N];
int n,m,j,k,l,i,o,p,u,v;
ll jc[N],ny[N],r1[N],r2[N];
ll ksm(ll o,ll t)
{
ll yy=1;
for(;t;t>>=1,o=o*o%mo)
if(t%2)yy=yy*o%mo;
return yy;
}
int min(int a,int b)
{if(a<b)return a;else return b;}
ll C(ll a,ll b)
{
return (jc[a]*ny[b]%mo)*ny[a-b]%mo;
}
void work1()
{
int k=0,v=0;
fo(i,1,n)if(!r1[i])e[++k]=i;
fo(i,1,k){
for(;e[i]>d[v+1]&&v<k;)v++;
least[i]=v;
}
fo(i,0,k)g1[i][0]=1;
fo(i,1,k)
fo(l,1,min(least[i],i))
g1[i][l]=(g1[i-1][l]+g1[i-1][l-1]*(least[i]-l+1))%mo;
f1[k]=g1[k][k];
fd(i,k-1,1){
f1[i]=g1[k][i]*jc[k-i]%mo;
fo(j,i+1,k)f1[i]=(f1[i]-f1[j]*C(j,i))%mo;
}
f1[0]=jc[k];
fo(i,1,k)f1[0]=(f1[0]-f1[i])%mo;
}
void work2()
{
int k=0,v=0;
fd(i,n,1)if(!r2[i])e[++k]=i;
fo(i,1,k){
for(;e[i]<c[v+1]&&v<k;)v++;
least[i]=v;
}
fo(i,0,k)g2[i][0]=1;
fo(i,1,k)
fo(l,1,min(least[i],i))
g2[i][l]=(g2[i-1][l]+g2[i-1][l-1]*(least[i]-l+1))%mo;
f2[k]=g2[k][k];
fd(i,k-1,1){
f2[i]=g2[k][i]*jc[k-i]%mo;
fo(j,i+1,k)f2[i]=(f2[i]-f2[j]*C(j,i))%mo;
}
f2[0]=jc[k];
fo(i,1,k)f2[0]=(f2[0]-f2[i])%mo;
}
int main()
{
cin>>n>>m;
jc[0]=ny[0]=1;
fo(i,1,n)jc[i]=jc[i-1]*i%mo,ny[i]=ksm(jc[i],mo-2);
fo(i,1,n)scanf("%d",&a[i]);
fo(i,1,n)scanf("%d",&b[i]);
fo(i,1,n){
if(!a[i])d[++u]=b[i]; r1[a[i]]++;
if(!b[i])c[++v]=a[i]; r2[b[i]]++;
if((a[i]*b[i]))m-=(a[i]>b[i]);
}
sort(d+1,d+u+1); sort(c+1,c+v+1);
fo(i,1,v/2)swap(c[i],c[v-i+1]);
work1(); work2();
ll ans;
fo(i,1,m)
ans=(ans+f1[i]*f2[m-i])%mo;
ans=(ans+mo)%mo;
printf("%lld",ans);
}