感觉做完这题已经没有什么题害怕了呢(算了当我没说)
首先安利一个写的很好的题解orz
http://www.cnblogs.com/dyllalala/p/3900077.html
写的挺详细的了,但是我总要写点什么吧,于是再解释一下做法…….
首先可以把题意转化一下,如果
(n+k)mod2=1
那肯定是没有满足要求的情况了,如果不为1,问题就是要求糖果大于药片的恰好有
m=(n+k)/2
组
a代表糖果,b代表药片
那么 (看题解) 不考虑要恰好有m组,只考虑至少m组易得一个DP:
先排一个序,然后处理一个数组pos,pos[i]表示最大的j使得
a[i]>b[j]
设
f[i][j]
为a前i个数和b数组匹配,保证有至少j组a大于b(可能大于j组)
f[i][j]=f[i−1][j]+f[i−1][j−1]∗(pos[i]−(j−1))
f[i−1][j] 比较好理解, f[i−1][j−1]∗(pos[i]−(j−1)) 的话,因为 i−1 匹配了 j−1 个,所以 ai 这个位置只有 (pos[i]−(j−1)) 个数可选
现在得到了f数组,但我们不能将 f[n][m] 直接作为答案,因为我们只能保证a数组有m个数和b数组里的m个数匹配,但不知道剩下的数的匹配情况,所以这里用容斥去重
设 g[i] 表示恰好有i组a大于b
g[i]=f[n][i]∗(n−i)!−∑g[j]∗Cij,(i<j<=n)
因为不知道a里面剩下的n-i个数是怎么匹配的,但是一定有 (n−i)! 种匹配情况,这些情况里包含了恰好有j组a大于b的情况 (i<j) ,j组被计算到的次数是 Cij 种,所以减去, g[m] 即是答案
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const ll Mod=1e9+9;
const int maxn = 2100;
int pos[maxn],n,m;
ll a[maxn],b[maxn];
ll f[maxn][maxn],c[maxn][maxn],N[maxn],p[maxn];
ll g[maxn];
ll exgcd(ll a,ll b,ll &x,ll &y)
{
if(a==0)
{
x=0;y=1;
return b;
}
ll tx,ty;
ll d=exgcd(b%a,a,tx,ty);
x=ty-b/a*tx;
y=tx;
return d;
}
int main()
{
scanf("%d%d",&n,&m);
if((n-m)&1){printf("0\n");return 0;}
m=(n+m)>>1;
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
for(int i=1;i<=n;i++)scanf("%lld",&b[i]);
sort(a+1,a+n+1);
sort(b+1,b+n+1);
for(int i=1;i<=n;i++)
{
int p=0;
while(p<n&&b[p+1]<a[i])p++;
pos[i]=p;
}
ll tmp;
for(int i=1;i<=n;i++)
{
exgcd(i,Mod,N[i],tmp);
N[i]=((N[i]%Mod)+Mod)%Mod;
}
p[0]=1;
for(int i=1;i<=n;i++)
{
tmp=1;p[i]=1;
for(int j=1;j<=i;j++)
{
tmp=(tmp*(ll)(i-j+1))%Mod;
tmp=(tmp*N[j])%Mod;
c[i][j]=tmp;
p[i]=(p[i]*(ll)j)%Mod;
}
}
f[0][0]=1;
for(int i=1;i<=n;i++)
{
for(int j=0;j<=i;j++)
{
if(pos[i]>=j)
f[i][j]=(f[i-1][j]+f[i-1][j-1]*(pos[i]-j+1))%Mod;
else f[i][j]=0;
}
}
for(int i=n;i>=m;i--)
{
g[i]=f[n][i]*p[n-i];
for(int j=i+1;j<=n;j++)
{
g[i]=((g[i]-g[j]*c[j][i])%Mod+Mod)%Mod;
}
}
printf("%lld\n",g[m]);
return 0;
}