【NOIP2017提高组模拟12.17】向再见说再见

Description

【NOIP2017提高组模拟12.17】向再见说再见_第1张图片

Solution

我们现在的目的是,a队赢(k+n)/2和(n-k)/2的方案数。
我们考虑正难则反,我们a队肯定赢i次的情况=至少赢i次的情况-肯定赢j次的情况的出现次数(j>i)

我们先来考虑至少赢i次的情况。
我们设f[i][j]表示a队的前i的至少赢j次的情况(不考虑那些不确定的,因为要求至少的情况)
先把两个数组排序一下。
那么 f[i+1][j+1]+=f[i][j](d[i+1]j) ——d[i]表示b队中有多少个比a[i]小的,那么要求推到i+1的胜利,就用能胜利的总人数减去已经胜利的总人数(因为排序之后,前面能胜利的人数后面也一定可以胜利)
还有 f[i+1][j]+=f[i][j] ——没有胜利,就不考虑胜利的情况数。

知道了胜利的情况,那么要怎么去求至少胜利i个人的情况呢?
我们设g[i]表示n个人中,至少胜利i个人
g[i]=f[n][i](ni)!
因为,我们已经胜利了i次,说明了已经确定了i个位置的情况,但是还有n-i个位置的情况没有确定,所以要乘上n-i个位置的全排列个数及(n-i)!

那么现在我们来考虑一下肯定赢i次的情况。
我们设h[i]表示n个数中肯定赢i次的情况。
根据上面的正难则反,我们枚举j,那么现在的问题就是怎么就h[j]的出现次数?

我们想想一个已经确定了选了i个的情况,那么要加上i-j个才能转化成j的情况,那么我们要在已经确定了i个基础上加上上j-i个,就变成了j个,方案数为 Cjij=Cij ,那么对于一个j就要 Cij 个i可以转化成它,那么对于h[j]个j一共的方案数就是 Cijh[j]
所以 h[i]=g[i]j>iCijh[j]
然后就没有了。

Code

#include
#include
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int maxn=2007,mo=1e9+7;
ll i,j,k,l,t,n,m,ans;
ll a[maxn],b[maxn];
ll f[maxn][maxn],h[maxn],g[maxn],c[maxn][maxn],d[maxn];
ll fact[maxn];
int main(){
//  freopen("fan.in","r",stdin);
    scanf("%lld%lld",&n,&k);
    fo(i,1,n)scanf("%d",&a[i]);
    fo(i,1,n)scanf("%d",&b[i]);
    fact[0]=1;fo(i,1,n)fact[i]=fact[i-1]*i%mo;
    sort(a+1,a+1+n);sort(b+1,b+1+n);
    fo(i,1,n){
        fo(j,1,n)if(b[j]
    }
    if((n+k)%2)printf("0\n");
    else{
        fo(i,1,n)c[i][0]=c[0][i]=1;
        fo(i,1,n){
            fo(j,1,i)c[i][j]=(c[i-1][j]+c[i-1][j-1])%mo;
        }
        c[0][0]=1;f[0][0]=1;
        fo(i,0,n){
            fo(j,0,n){
                if(!f[i][j])continue;
                f[i+1][j+1]=(f[i][j]*(d[i+1]-j)+f[i+1][j+1])%mo;
                f[i+1][j]=(f[i+1][j]+f[i][j])%mo;
            }
        }
        fo(i,0,n)g[i]=f[n][i]*fact[n-i]%mo;
        fod(i,n,1){
            h[i]=g[i];
            fo(j,i+1,n){
                h[i]=(h[i]-c[j][i]*h[j]%mo)%mo;
            }
            h[i]=(h[i]+mo)%mo;
        }
        if(!k)ans=h[(n+k)/2];
        else ans=(h[(n+k)/2]+h[(n-k)/2])%mo;
        printf("%lld\n",ans);
    }
}

你可能感兴趣的:(noip,DP)