用来学习二项式反演的题目
大于等于/小于等于 反演出 恰好等于
设前者为f(n),后者为g(n),则有$f(n)=\sum\limits_{i=0}^nC_n^ig(n)<->g(n)=\sum\limits_{i=0}^n(-1)^iC_n^if(i)$
这里我们$n^2$地dp求出$f(i)$表示a>b的组数大于等于i的方案数然后套二项式反演即可。设$dp[i][j]$表示前i个物品产生了j组a>b的配对的方案数,那么$dp[i][j]=dp[i-1][j]+(lst-j+1)*dp[i-1[j-1]$,其中lst表示b中小于a_i的数的数目,最后$f(i)=dp[n][i]*(n-i)!$。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=2005,mod=1e9+9; 6 int n,m,ans,a[N],b[N],lst[N]; 7 int f[N],g[N],fac[N],inv[N],dp[N][N]; 8 void Add(int &x,int y) 9 { 10 x+=y; 11 if(x<0) x+=mod; 12 else if(x>=mod) x-=mod; 13 } 14 int Qpow(int x,int k) 15 { 16 if(k==1) return x; 17 int tmp=Qpow(x,k/2); 18 return k%2?1ll*tmp*tmp%mod*x%mod:1ll*tmp*tmp%mod; 19 } 20 int C(int a,int b) 21 { 22 return 1ll*fac[a]*inv[b]%mod*inv[a-b]%mod; 23 } 24 void Pre() 25 { 26 fac[0]=inv[0]=1,m=(n+m)/2; 27 for(int i=1;i<=2000;i++) fac[i]=1ll*fac[i-1]*i%mod; 28 inv[2000]=Qpow(fac[2000],mod-2); 29 for(int i=1999;i;i--) inv[i]=1ll*inv[i+1]*(i+1)%mod; 30 } 31 int main() 32 { 33 scanf("%d%d",&n,&m),Pre(); 34 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 35 for(int i=1;i<=n;i++) scanf("%d",&b[i]); 36 sort(a+1,a+1+n),sort(b+1,b+1+n),dp[0][0]=1; 37 for(int i=1;i<=n;i++) lst[i]=lower_bound(b+1,b+1+n,a[i])-b-1; 38 for(int i=1;i<=n;i++) 39 { 40 dp[i][0]=dp[i-1][0]; 41 for(int j=1;j<=n;j++) 42 dp[i][j]=(dp[i-1][j]+1ll*max(0,lst[i]-j+1)*dp[i-1][j-1]%mod)%mod; 43 } 44 for(int i=1;i<=n;i++) g[i]=1ll*dp[n][i]*fac[n-i]%mod; 45 for(int i=m;i<=n;i++) 46 Add(ans,(((i-m)&1)?-1ll:1ll)*C(i,m)*g[i]%mod); 47 printf("%d",ans); 48 return 0; 49 }