解题:BZOJ 3622 已经没有什么好害怕的了·

题面

用来学习二项式反演的题目

大于等于/小于等于 反演出 恰好等于

设前者为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 }
View Code

猜你喜欢

转载自www.cnblogs.com/ydnhaha/p/10432615.html