P4859 已经没有什么好害怕的了(二项式反演)
Posted chtholly
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P4859 已经没有什么好害怕的了(二项式反演)相关的知识,希望对你有一定的参考价值。
题目
思路
显然是恰好有(frac{n+k}{2})组(a>b)
令(f(i,j))表示前(i)个糖果,已经有(j)组(a>b),剩下的没管的方案数
对(a)数组从小到大排序,设(r_i)表示比(a_i)小的(b)个数,那么(r_i)是递增的
有状态转移方程(f(i,j) = f(i-1,j) + f(i-1,j-1) imes (r_i-j+1))
对于每个(f(n,i)),由于剩下的(n-i)对不知道大小情况,那么有(f(n,i) imes (n-i)!)种情况至少有(i)个匹配
设(g_i)表示恰好有(i)个匹配,那么(f(n,i) imes (n-i)! = Sigma_{j=i}^n C(j,i) imes g_i)
二项式反演后就是(g_i = Sigma_{j=i}^n (-1)^{j-i}C(j,i) imes f(n,j) imes (n-j)!)
#include<bits/stdc++.h>
#define N 2005
using namespace std;
typedef long long ll;
const ll mod = 1000000009;
int n,k,a[N],b[N],r[N];
ll f[N][N];
ll fac[N],ifac[N];
template <class T> inline T Max(T a,T b) { return a > b ? a : b; }
template <class T> inline T Min(T a,T b) { return a < b ? a : b; }
template <class T> void read(T &x)
{
char c;int sign=1;
while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
while((c=getchar())>='0'&&c<='9') x=(x<<1)+(x<<3)+c-48; x*=sign;
}
ll qp(ll a,ll b) { ll ret=1; for(;b;b>>=1,a=a*a%mod) if(b&1) ret=ret*a%mod; return ret; }
ll C(int n,int m) { return n>=m ? fac[n]*ifac[m]%mod*ifac[n-m]%mod : 0; }
void init(int maxn)
{
fac[0]=1; for(int i=1;i<=maxn;++i) fac[i]=fac[i-1]*i%mod;
ifac[maxn]=qp(fac[maxn],mod-2);
for(int i=maxn-1;i>=0;--i) ifac[i]=ifac[i+1]*(i+1)%mod;
}
int main()
{
read(n);read(k);
for(int i=1;i<=n;++i) read(a[i]);
for(int i=1;i<=n;++i) read(b[i]);
sort(a+1,a+n+1); sort(b+1,b+n+1);
if((n+k)&1) { printf("0"); return 0; }
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
r[i]+=(a[i]>b[j]);
init(2000);
f[0][0]=1;
for(int i=1;i<=n;++i)
{
f[i][0]=f[i-1][0];
for(int j=1;j<=i;++j) f[i][j] = (f[i-1][j] + f[i-1][j-1] * max(0,r[i]-j+1))%mod;
}
ll ans=0;
k=(n+k)/2;
for(int i=k;i<=n;++i) ans = (ans + ((i-k)&1 ? -1 : 1) * C(i,k) * f[n][i]%mod *fac[n-i]%mod)%mod;
printf("%lld
",(ans%mod+mod)%mod);
return 0;
}
以上是关于P4859 已经没有什么好害怕的了(二项式反演)的主要内容,如果未能解决你的问题,请参考以下文章