题目链接
https://www.lydsy.com/JudgeOnline/problem.php?id=3622
题解
对糖果和药片都排一遍序,设
c
n
t
[
i
]
cnt[i]
cnt[i]表示对于
i
i
i号糖果,比他小的药片有多少个,
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示对于前
i
i
i个糖果和对应的
i
i
i个药片,糖果比药片至少多
j
j
j个的方案数是多少,不考虑其他的情况,dp转移
f
[
i
]
[
j
]
f[i][j]
f[i][j]。
f
[
i
]
[
j
]
=
f
[
i
−
1
]
[
j
]
+
f
[
i
−
1
]
[
j
−
1
]
×
(
c
n
t
[
i
]
−
j
+
1
)
f[i][j]=f[i-1][j]+f[i-1][j-1]\times (cnt[i]-j+1)
f[i][j]=f[i−1][j]+f[i−1][j−1]×(cnt[i]−j+1)
最后容斥求出糖果比药片恰好多
k
k
k个的方案数
a
n
s
=
∑
i
=
k
n
(
−
1
)
i
−
k
(
i
k
)
f
[
n
]
[
i
]
(
n
−
i
)
!
ans=\sum_{i=k}^n (-1)^{i-k} \binom{i}{k} f[n][i] (n-i)!
ans=i=k∑n(−1)i−k(ki)f[n][i](n−i)!
代码
#include <cstdio>
#include <algorithm>
int read()
{
int x=0,f=1;
char ch=getchar();
while((ch<'0')||(ch>'9'))
{
if(ch=='-')
{
f=-f;
}
ch=getchar();
}
while((ch>='0')&&(ch<='9'))
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
const int maxn=2000;
const int mod=1000000009;
int n,k,candy[maxn+10],pill[maxn+10],cnt[maxn+10],f[maxn+10][maxn+10],fac[maxn+10],ifac[maxn+10];
int C(int a,int b)
{
if(b>a)
{
return 0;
}
return 1ll*fac[a]*ifac[b]%mod*ifac[a-b]%mod;
}
int main()
{
n=read();
k=read();
if((n-k)&1)
{
puts("0");
return 0;
}
k=((n-k)>>1)+k;
for(int i=1; i<=n; ++i)
{
candy[i]=read();
}
for(int i=1; i<=n; ++i)
{
pill[i]=read();
}
fac[0]=1;
for(int i=1; i<=n; ++i)
{
fac[i]=1ll*fac[i-1]*i%mod;
}
ifac[0]=ifac[1]=1;
for(int i=2; i<=n; ++i)
{
ifac[i]=1ll*(mod-mod/i)*ifac[mod%i]%mod;
}
for(int i=1; i<=n; ++i)
{
ifac[i]=1ll*ifac[i]*ifac[i-1]%mod;
}
std::sort(candy+1,candy+n+1);
std::sort(pill+1,pill+n+1);
int now=0;
for(int i=1; i<=n; ++i)
{
while((now<n)&&(pill[now+1]<candy[i]))
{
++now;
}
cnt[i]=now;
}
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>0)&&(cnt[i]-j+1>0))
{
f[i][j]=(f[i][j]+1ll*f[i-1][j-1]*(cnt[i]-j+1))%mod;
}
}
}
int ans=0;
for(int i=k; i<=n; ++i)
{
ans=(ans+(((i-k)&1)?(mod-1ll):1ll)*C(i,k)%mod*f[n][i]%mod*fac[n-i])%mod;
}
printf("%d\n",ans);
return 0;
}