已经没有什么好害怕的了
作者:互联网
Link
Solution
容易将题目转换为使糖果和药片两两匹配,使得其中恰好有 \(\frac{n+k}{2}\) 组糖果权值比药片大。容易知道当 \(n+k\) 为奇数时无解。
不妨令 \(m=\frac{n+k}{2}\) 。根据反演套路,我们只需要求出
\[G(m)=\sum_{i=m}^n (-1)^{i-m} \binom{i}{m} F(i) \]其中 \(F(i)\) 表示强制令其中 \(i\) 组是合法的,剩余的随便匹配的方案。和以往做过的反演题不同,这里的 \(F\) 并不容易求出,因为只考虑组合意义的话实在无从下手。所以我们转而思考其它的方法。将糖果和药片升序排序后,容易知道对于一个糖片,能产生合法匹配的药片是一个前缀。而且随着糖果递增,这个前缀的长度也在递增,也就是说前面的糖片能匹配的,后面也行。所以前面的糖果无论怎么匹配,在算后面的匹配时,都不会造成太多的影响,直接从决策集合中减去即可。有阶段性。那么这个方案数就很好算了,可以直接 dp。用 \(dp_{i,k}\) 表示前 \(i\) 个糖果中强制令 \(k\) 对合法的方案,那么
\[dp_{i,k}=dp_{i-1,k}+(a_i-(k-1))\times dp_{i-1,k-1} \]其中 \(a_{i}\) 表示比第 \(i\) 个糖果权值小的药片个数,这个直接二分即可求。
再将 \(dp\) 乘上剩下随便匹配的方案 \((n-k)!\),得 \(F(k)=dp_{n,k}\times (n-k)!\)
复杂度 \(O(n^2)\)
#include<stdio.h>
#include<algorithm>
using namespace std;
#define N 2007
#define Mod 1000000009
#define ll long long
int n,a[N],b[N],K;
ll dp[N][N],fac[N],inv[N];
ll qpow(ll x,ll y){
ll ret=1,cnt=0;
while(y>=(1ll<<cnt)){
if(y&(1ll<<cnt)) ret=(ret*x)%Mod;
x=(x*x)%Mod,cnt++;
}
return ret;
}
ll C(int x,int y){return x<y? 0:fac[x]*inv[y]%Mod*inv[x-y]%Mod;}
int main(){
// freopen("data.in","r",stdin);
scanf("%d%d",&n,&K);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) scanf("%d",&b[i]);
if((n+K)&1) return printf("0"),0;
else K=(n+K)>>1;
sort(a+1,a+1+n),sort(b+1,b+1+n);
for(int i=1;i<=n;i++)
a[i]=lower_bound(b+1,b+1+n,a[i])-b-1;
// for(int i=1;i<=n;i++) printf("%d ",a[i]);
dp[0][0]=1;
for(int i=1;i<=n;i++){
dp[i][0]=dp[i-1][0];
for(int k=1;k<=i;k++)
dp[i][k]=(dp[i-1][k]+max(0,a[i]-k+1)*dp[i-1][k-1]%Mod)%Mod;
}
fac[0]=1;
for(int i=1;i<N;i++) fac[i]=fac[i-1]*i%Mod;
inv[N-1]=qpow(fac[N-1],Mod-2);
for(int i=N-2;~i;i--) inv[i]=inv[i+1]*(i+1)%Mod;
ll ans=0;
for(int i=K,op=1;i<=n;i++,op=-op)
ans=(ans+op*C(i,K)*dp[n][i]%Mod*fac[n-i]%Mod+Mod)%Mod;
printf("%lld",ans);
}
标签:匹配,药片,什么,害怕,已经,糖果,ll,dp,define 来源: https://www.cnblogs.com/wwlwQWQ/p/14317472.html