zoukankan      html  css  js  c++  java
  • 度度熊与组题 组合数+DP

    度度熊与组题

    沃老师在出比赛的题目时遇到麻烦啦!

    遇到的麻烦如下:

    现在沃老师手上有 2n 道题,题目编号由 1∼2n,已知第 i 道题难度为 ai,这些题的难度还满足当 i<j 时 ai≤aj。现在沃老师想把这些题目分在两套比赛上,每套比赛会被分到 n 道题,每道题都会恰出现在其中一场比赛中。假设分配完后,第一套题难度第 i 小的题的难度为 ci (第 i 小是指不去重的的第 i 小,例如有四道题难度分别是 1,1,2,3 时,难度第 3 小的题是难度是 2),第二套题难度第 i 小的题为 di,沃老师定义两场比赛的难度相似度为 ∑ni=1|ci−di|,且沃老师希望分配完题目后,两场比赛的难度相似度尽可能的小。

    看到这你可能会觉得这算什么麻烦,难度相似度的最小值不就是 ∑ni=1(a2i−a2i−1) 嘛?

    是的,光是要使难度相似度最小并不构成沃老师的麻烦,但沃老师是个好奇宝宝,他还想知道,有多少种分配题目的方式,能使难度相似度最小呢?这个问题可能就没那么简单了。

    于是沃老师就来拜托聪明的度熊帮他解决他心中的困惑,各位也帮忙算算吧。

    请输出分配题目的方式数量除以 109+7 的余数。

    两种分配方式 A 和 B 不同当且仅当存在某道题出现在 A 的第一套比赛中,却没有出现在 B 的第一套比赛中。举例来说,当 n=1 时,第一套比赛含有题目 1 第二套比赛含有题目 2 和 第一套比赛含有题目 2 第二套比赛含有题目 1 是不同的。


    一个很好的引理: 最优解 对于 (<=v-1)(<=v) 的 个数绝对值差不超过1
    然后我们就可以枚举分配然后DP

    #include<bits/stdc++.h>
    using namespace std;
    #define maxnn 4000
    #define mod 1000000007
    #define ll long long 
    ll f[maxnn];
    ll sum[maxnn];
    ll dp[maxnn];
    ll T,n;
    ll a[maxnn];
    ll num[maxnn];
    ll ksm(int a,int b)
    {
        ll ans=1;
        while(b)
        {
            if(b&1) ans=ans*a%mod;
            a=a*a%mod;
            b>>=1;
        }
        return ans;
    }
    ll  C(int n,int m)
    {
        if(n==m||m==0) return 1;
        ll A=1,B=1;
        for(int i=0;i<m;i++)
        {
            B*=(i+1)%mod;
            A=A*(n-i)%mod;
        }
        return A*ksm(B,mod-2);
    }
    int main(){
        int T;
        scanf("%d",&T);
        while(T--){
            int n;
            scanf("%d",&n);
            int up=n<<1;
            for(int i=1;i<=up;i++){
                scanf("%d",&a[i]);
                num[i]=0;
            } 
            for(int i=1;i<=up;i++) num[a[i]]++;
            dp[0]=1;
            ll sum=0;
            for(int i=1;i<=up;i++){
                if((sum&1)==0&&(num[i]&1)==0){ 
                    dp[i]=dp[i-1]*C(num[i],num[i]>>1)%mod; 
                }
                else if((sum&1)==0&&(num[i]&1)==1){
                    dp[i]=dp[i-1]*C(num[i],num[i]>>1)*2%mod; 
                }
                else if((sum&1)==1&&(num[i]&1)==1){
                    dp[i]=dp[i-1]*C(num[i],num[i]>>1)%mod; 
                }
                else { 
                    dp[i]=dp[i-1]*C(num[i],num[i]>>1)%mod;
                    if(num[i]){
                        dp[i]+=dp[i-1]*C(num[i],(num[i]-2)>>1)%mod;
                        dp[i]%=mod;
                    }  
                }
                sum+=num[i];
            }
            printf("%lld
    ",dp[up]);
        } 
        return 0;
    }
    
    刀剑映出了战士的心。而我的心,漆黑且残破
  • 相关阅读:
    C++ std::forward_list
    MyBatis基础入门《十三》批量新增数据
    MyBatis基础入门《十二》删除数据
    MyBatis基础入门《十 一》修改数据
    MyBatis基础入门《十》添加数据
    MyBatis基础入门《九》ResultMap自动匹配
    MyBatis基础入门《八》查询参数传入Map
    MyBatis基础入门《七》查询参数传入对象
    MyBatis基础入门《六》Like模糊查询
    MyBatis基础入门《五》核心配置文件
  • 原文地址:https://www.cnblogs.com/OIEREDSION/p/11434287.html
Copyright © 2011-2022 走看看