Description
Input
Output
Sample Input
4 2
5 35 15 45
40 20 10 30
5 35 15 45
40 20 10 30
Sample Output
4
HINT
输入的2*n个数字保证全不相同。
还有输入应该是第二行是糖果,第三行是药片
Source
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~DP+组合数+容斥原理~
先将a和c从小到大排序,预处理出g[i]表示使得a[i]>c[j]成立的最大j。
用f[i][j]表示目前到第i个糖,至少有j对糖>药的方案数,那么f[i][j]=f[i-1][j]+f[i-1][j-1]*(g[i]-j+1)。
然后我们用容斥原理,枚举剩余的对中还有多少种满足条件,得f[n][i]=f[n][i]*(n-i)!-sum{f[n][j]*c(j,i)}。
注意输入的k不是我写的k,要自己求得;如果(n-k)&1==1的话,答案是0。
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
const int mod=1e9+9;
int n,K,a[2001],c[2001],g[2001],f[2001][2001],k[2001][2001],sheng[2001],jiang[2001];
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0' && ch<='9') {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int mi(int u,int v)
{
int now=1;
for(;v;v>>=1,u=(ll)u*u%mod) if(v&1) now=(ll)now*u%mod;
return now;
}
void init()
{
sheng[0]=jiang[0]=1;
for(int i=1;i<=n;i++) sheng[i]=(ll)sheng[i-1]*i%mod;
jiang[n]=mi(sheng[n],mod-2);
for(int i=n-1;i;i--) jiang[i]=(ll)jiang[i+1]*(i+1)%mod;
}
int C(int n,int m)
{
return (ll)sheng[n]*jiang[m]%mod*jiang[n-m]%mod;
}
void add(int &a,int b)
{
a=a+b>=mod ? a+b-mod:a+b;
}
void sub(int &a,int b)
{
a=a>=b ? a-b:a-b+mod;
}
int main()
{
n=read();K=read();
if((n-K)&1)
{
puts("0");return 0;
}
K=(n+K)>>1;init();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=n;i++) c[i]=read();
sort(a+1,a+n+1);sort(c+1,c+n+1);
for(int i=1,j=1;i<=n;i++)
{
for(;a[i]>c[j] && j<=n;j++);
g[i]=--j;
}
f[0][0]=1;
for(int i=1;i<=n;i++)
for(int j=0;j<=i;j++)
{
f[i][j]=f[i-1][j];
if(j && g[i]-j+1>0) add(f[i][j],(ll)f[i-1][j-1]*(g[i]-j+1)%mod);
}
for(int i=n;i>=K;i--)
{
f[n][i]=(ll)f[n][i]*sheng[n-i]%mod;
for(int j=i+1;j<=n;j++) sub(f[n][i],(ll)f[n][j]*C(j,i)%mod);
}
printf("%d\n",f[n][K]);
return 0;
}