您的位置:首页 > 编程语言 > C语言/C++

BZOJ 3622 已经没有什么好害怕的了

2017-06-29 11:43 323 查看

Description



Input



Output



Sample Input

4 2

5 35 15 45

40 20 10 30

Sample Output

4

HINT



输入的2*n个数字保证全不相同。

还有输入应该是第二行是糖果,第三行是药片

Source

2014湖北省队互测week2

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

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
[i]=f
[i]*(n-i)!-sum{f
[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
=mi(sheng
,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
*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
[i]=(ll)f
[i]*sheng[n-i]%mod;
for(int j=i+1;j<=n;j++) sub(f
[i],(ll)f
[j]*C(j,i)%mod);
}
printf("%d\n",f
[K]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息