[bzoj3622]已经没有什么好害怕的了

来自FallDream的博客,未经允许,请勿转载,谢谢。


n<=2000 

 

这题有点神....

先考虑dp,f[i][j]表示前i个中确定了j对a>b的方案数,令num[i]表示A[i]大于多少个B中的元素,那么

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

然后考虑去重,令F[i]表示全部确定之后恰好有i对a>b的方案数,那么$F[i]=f[n][i]*(n-i)!-\sum_{j=i+1}^{n}F[j]*C(j,i)$

复杂度n^2

#include<algorithm>
#include<iostream>
#include<cstdio>
#define MN 2000
#define mod 1000000009
using namespace std;
inline int read()
{
    int x = 0 , f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}
int p[MN+5],inv[MN+5],n,k,f[MN+5][MN+5],A[MN+5],B[MN+5],num[MN+5];
inline void R(int&x,int y){x+=y;x>=mod?x-=mod:0;}
inline int C(int n,int m){return 1LL*p[n]*inv[m]%mod*inv[n-m]%mod;}
int main()
{
    n=read();k=read();if((n+k)&1) return 0*puts("0");
    for(int i=1;i<=n;++i) A[i]=read();
    for(int i=1;i<=n;++i) B[i]=read();
    sort(A+1,A+n+1);sort(B+1,B+n+1);
    for(int i=1;i<=n;++i) num[i]=upper_bound(B+1,B+n+1,A[i])-B-1;
    f[0][0]=p[0]=p[1]=inv[0]=inv[1]=1;
    for(int i=1;i<=n;++i)
        for(int j=0;j<=i;++j)
        {
            if(j&&num[i]-j+1>0) R(f[i][j],1LL*f[i-1][j-1]*(num[i]-j+1)%mod);
            R(f[i][j],f[i-1][j]);
        }
    for(int i=2;i<=n;++i) p[i]=1LL*p[i-1]*i%mod,inv[i]=1LL*(mod-mod/i)*inv[mod%i]%mod;
    for(int i=2;i<=n;++i) inv[i]=1LL*inv[i]*inv[i-1]%mod;
    for(int i=n-1;~i;--i)
    {
        f[n][i]=1LL*f[n][i]*p[n-i]%mod;
        for(int j=i+1;j<=n;++j)
            R(f[n][i],mod-(1LL*f[n][j]*C(j,i)%mod));
    }
    printf("%d\n",f[n][n+k>>1]);
    return 0;
}
posted @ 2017-07-05 09:29  FallDream  阅读(278)  评论(0编辑  收藏  举报