1. 程式人生 > >已經沒有什麽好害怕的了——二項式反演+經典套路

已經沒有什麽好害怕的了——二項式反演+經典套路

problem bool register print ace 多項式 clas std digi

題面:已經沒有什麽好害怕的了

首先,大k個,k=(n+k)/2,糖果多的恰好有k組

一個通用技巧是:

找到兩個數組f,g

f範圍寬松好統計,g範圍嚴格難統計但是和答案有直接關系,

這樣,只要得到f和g的關系,就可以找到答案!

經常是可以得到f由g的表達式,然後斯特林反演或者二項式反演得到g的求法

也可以用多項式科技

數論函數的反演也可以這麽做。

這個題就這樣做:

涉及大小關系,先把A,B從小到大排序便於決策

稱糖果比藥片大的配對叫“優秀”

設f[k]表示,“欽定選擇k組優秀,其他任意選”方案數。

g[k]表示,“恰好k組優秀”。g[K]就是答案

f和g的關系式:

$f[i]=\sum_{j=i}^nC(j,i)g[j]$

二項式反演:

$g[i]=\sum_{j=i}^n(-1)^{j-i}C(j,i)*f[j]$

任意選擇i個都構成一組欽定。

計算f

DP,$f[i][j]$前i個,欽定了j個

$f[i][j]=f[i-1][j]+f[i-1][j-1]*(small[i]-(j-1))$

第i個選擇或者不選擇,不選擇先不給予匹配,選擇,就從比$a_i$小的$b_i$中選擇,排好序了,所以直接$-(j-1)$就是剩下的

最後再給其他沒有給予匹配的隨便給予:$f[i]*=(n-i)!$

然後根據反演式子。

或者,如果有時難以反演,就倒著求出每個g[i],用g[i+1~n]和f[i]得到g[i]

代碼:

#include<bits/stdc++.h>
#define
reg register int #define il inline #define numb (ch^‘0‘) using namespace std; typedef long long ll; il void rd(int &x){ char ch;x=0;bool fl=false; while(!isdigit(ch=getchar()))(ch==-)&&(fl=true); for(x=numb;isdigit(ch=getchar());x=x*10+numb); (fl==true)&&(x=-x); }
namespace Miracle{ const int mod=1e9+9; const int N=2002; int n,k; int a[N],b[N]; int f[N][N],g[N]; int C[N][N]; int qm(int x,int y){ int ret=1; while(y){ if(y&1) ret=(ll)ret*x%mod; x=(ll)x*x%mod; y>>=1; } return ret; } int main(){ rd(n);rd(k); if((n+k)&1){ puts("0");return 0; } k=(n+k)>>1; for(reg i=1;i<=n;++i) rd(a[i]); for(reg j=1;j<=n;++j) rd(b[j]); sort(a+1,a+n+1);sort(b+1,b+n+1); int smal=0; f[0][0]=1; for(reg i=1;i<=n;++i){ while(smal<n&&b[smal+1]<a[i])++smal; for(reg j=0;j<=i;++j){ if(j&&smal>(j-1))f[i][j]=((ll)f[i-1][j-1]*(smal-(j-1)))%mod; f[i][j]=(f[i][j]+f[i-1][j])%mod; // cout<<" i j "<<i<<" "<<j<<" : "<<f[i][j]<<endl; } } int jie=1; for(reg j=n;j>=0;--j){ if(n-j)jie=(ll)jie*(n-j)%mod; f[n][j]=((ll)f[n][j]*jie)%mod; // cout<<" ff "<<f[n][j]<<endl; } C[0][0]=1; for(reg i=1;i<=n;++i){ C[i][0]=1; for(reg j=1;j<=n;++j){ C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod; } } for(reg i=n;i>=k;--i){ if(i==n){ g[i]=f[n][i]; }else{ int sum=0; for(reg j=i+1;j<=n;++j){ sum=(sum+(ll)C[j][i]*g[j]%mod)%mod; } g[i]=(ll)((ll)f[n][i]-sum+mod)%mod; } } printf("%d",g[k]); return 0; } } signed main(){ Miracle::main(); return 0; } /* Author: *Miracle* Date: 2019/2/18 8:32:07 */

已經沒有什麽好害怕的了——二項式反演+經典套路