题目大意:给出长度为n的a,b两个序列,元素互不相同。求有多少种匹配满足 ai>bi 比 ai<bi 多m对。
将问题转化一下,即求有多少种匹配其中
ai>bi
恰好为
n+m2
,其余均为
ai<bi
。
若设状态为
fi,j
表示a序列中前
i
个元素匹配完恰好有j对为
看到计数问题可以考虑容斥。
需要将状态设置得便于转移,将状态改为
fi,j
表示a序列中前
i
个元素至少匹配了
先将a,b序列排序,预处理出
fi,j=fi−1,j+fi−1,j−1×(maxxi−j+1)
利用容斥,设
gj
为a序列n个元素恰好匹配
j
组满足
gj=fn,j×facn−j−∑k=j+1k<=ngk×Cjk
至少匹配 j 组
#include <cstdio>
#include <algorithm>
#define N 2005
#define MOD 1000000009
using namespace std;
typedef long long LL;
int n,m,a[N],b[N],maxx[N];
LL f_pow(LL x,LL y) {
LL tmp=1;
while(y) {
if(y&1) (tmp*=x)%=MOD;
(x*=x)%=MOD;
y>>=1;
}
return tmp;
}
LL fac[N],inv[N],f[N][N],g[N];
void init() {
fac[1]=1;
for(LL i=2;i<=n;i++) fac[i]=(fac[i-1]*i)%MOD;
inv[n]=f_pow(fac[n],MOD-2);
for(LL i=n-1;i;i--) inv[i]=inv[i+1]*(i+1)%MOD;
return ;
}
LL C(int n,int m) { return fac[n]*inv[m]%MOD*inv[n-m]%MOD; }
int main() {
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",a+i);
for(int i=1;i<=n;i++) scanf("%d",b+i);
if(n+m&1) {
printf("0\n");
return 0;
}
(m+=n)/=2;
sort(a+1,a+n+1), sort(b+1,b+n+1);
for(int i=1;i<=n;i++) {
maxx[i]=maxx[i-1];
while(b[maxx[i]]<a[i] && maxx[i]<=n) maxx[i]++;
maxx[i]--;
}
init();
for(int i=0;i<=n;i++) f[i][0]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++)
f[i][j]=(f[i-1][j]+f[i-1][j-1]*max(0,maxx[i]-j+1))%MOD;
for(int i=n;i>=m;i--) g[i]=f[n][i]*fac[n-i]%MOD;
for(int i=n;i>=m;i--)
for(int j=i+1;j<=n;j++)
(g[i]+=MOD-g[j]*C(j,i)%MOD)%=MOD;
printf("%lld\n",g[m]);
return 0;
}