luoguP4859 已經沒有什麼好害怕的了(二項式反演)
阿新 • • 發佈:2020-08-04
luoguP4859 已經沒有什麼好害怕的了(二項式反演)
祭奠天國的bzoj。
題解時間
先特判 $ n - k $ 為奇數無解。
為了方便下記 $ m = ( n + k ) / 2 $ 為 $ A>B $ 的個數。
恰好改欽定。
設 $ dp( i , j ) $ 為考慮 $ A $ 的前 $ i $ 個數欽定 $ j $ 對 $ A>B $ 的方案數。
有欽定 $ g( i ) = dp( n , i ) \times ( n - i )! $ 。
然後直接二項式反演 $ f( m ) = \sum\limits_{ i = m }^{ n } ( - 1 )^{ i - m } \binom{ i }{ m } g( i ) $ 。
程式碼
#include<bits/stdc++.h> using namespace std; typedef long long lint; struct pat{int x,y;pat(int x=0,int y=0):x(x),y(y){}bool operator<(const pat &p)const{return x==p.x?y<p.y:x<p.x;}}; template<typename TP>inline void read(TP &tar) { TP ret=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){ret=ret*10+(ch-'0');ch=getchar();} tar=ret*f; } namespace RKK { const int N=2011,mo=1000000009; lint add(lint a,lint b){return (a+=b)>=mo?a-mo:a;} void doadd(lint &a,lint b){if(b<0) b+=mo;if((a+=b)>=mo) a-=mo;} lint fac[N],c[N][N]; void init() { fac[0]=1;for(int i=1;i<=2000;i++) fac[i]=fac[i-1]*i%mo; for(int i=0;i<=2000;i++) c[i][0]=1; for(int i=1;i<=2000;i++)for(int j=1;j<=i;j++) c[i][j]=add(c[i-1][j-1],c[i-1][j]); } int n,m,a[N],b[N]; lint dp[N][N],ans; int main() { init(),read(n),read(m);for(int i=1;i<=n;i++) read(a[i]);for(int i=1;i<=n;i++) read(b[i]);sort(a+1,a+1+n),sort(b+1,b+1+n); if((n-m)&1){puts("0");return 0;}m=(n+m)/2; for(int i=0;i<=n;i++) dp[i][0]=1; for(int i=1,k=1;i<=n;i++) { while(k<=n&&a[i]>b[k]) k++; for(int j=1;j<=n;j++) dp[i][j]=add(dp[i-1][j],dp[i-1][j-1]*(k-j)%mo); } for(int i=m;i<=n;i++) doadd(ans,(((i-m)&1)?-1ll:1ll)*c[i][m]*dp[n][i]%mo*fac[n-i]%mo); printf("%lld\n",ans); return 0; } } int main(){return RKK::main();}