题目
思路
显然是恰好有\(\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) \times (r_i-j+1)\)
对于每个\(f(n,i)\),由于剩下的\(n-i\)对不知道大小情况,那么有\(f(n,i)\times (n-i)!\)种情况至少有\(i\)个匹配
设\(g_i\)表示恰好有\(i\)个匹配,那么\(f(n,i) \times (n-i)! = \Sigma_{j=i}^n C(j,i)\times g_i\)
二项式反演后就是\(g_i = \Sigma_{j=i}^n (-1)^{j-i}C(j,i)\times f(n,j)\times (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\n",(ans%mod+mod)%mod);
return 0;
}
原文地址:https://www.cnblogs.com/Chtholly/p/11967407.html
时间: 2024-10-09 20:24:16