zoukankan      html  css  js  c++  java
  • Mythological VI

    Description

    (1...n)一共(n)个数。保证(n)为偶数。
    小M要把这(n)个数两两配对, 一共配成(n/2)对。每一对的权值是他们两个数的和。
    小M想要知道这(n)对里最大的权值的期望是多少。可怜的小M当然不知道啦,所以她向你求助。
    请输出答案对(10^9+7)取模的值。
      

    Input

    一行一个正整数,表示(n)
      

    Output

    一行一个整数,表示答案对(10^9+7)取模的值。
      

    Sample Input

    4
    

      

    Sample Output

    6
    

      

    HINT

    对于20%的数据, (nleq 10)
    对于40%的数据, (nleq 2*10^3)
    对于100%的数据, (nleq 5*10^5)
      
        
        
      

    Solution

      
    ​  首先可能的最大值最大为(n+(n-1)=2n-1)
      
    ​  考虑能不能枚举最大值(v),算出最大值等于每个(v)时的方案数,除以总方案数得到概率,再算出期望。
      
    ​  观察得出(vin [n+1,2n-1]),所以只要在这个区间内枚举即可。
      
    ​  可是考虑到计算最大值恰好等于(v)的方案数不是很可行,于是我们看看能不能转化成先求前缀和:(g[i])表示最大值小于等于(v)的方案数是多少。自然地,最大值等于(v)时的方案数为(g_v-g_{v-1})
      
    ​  下面看怎么求(g_v),记(a=lfloor frac v 2 floor)
      
    ​  首先这(n)个数中,有些比较特别:((a,n])这些数,必须选择位于([1,a])中的数,否则最大值可能超过(v)。那就先考虑这些数的匹配方法。
      
    ​  先看看(n)有多少种选法:(n)必须和([1,v-n])中的数匹配,共(v-n)种选择。
     
    ​  (n-1)呢?必须和([1,v-(n-1)])中的数匹配,共(v-n+1)种选择;但是(n)已经从([1,v-n])挑走了一个数,所以总选择方案减1,仍然是(v-n)种选择。
       
    ​  由此从大到小考虑((a,n]),发现每个数的可选择方案都是(v-n),那么为((x,n])(n-a)个数选择好匹配的总方案数为((v-n)^{n-a})
      
    ​  此时([1,a])个数中已有(n-a)个数被挑走做匹配了,剩下(a-(n-a)=2a-n)个数,由于它们都小于等于(a),所以剩下的数可以任意匹配而不会出现一对数权值之和大于(v)的情况。
      
    ​  记(f(x))表示(x)个点任意两两匹配的方案数,推一推就得知(f(x)=f(x-2)*(x-1)),意思就是一个点从其他(x-1)个点挑一个,移除这两个点后继续操作。
      
    ​  则剩下的数的方案为(f(2a-n))
      
      所以(g_v=(v-n)^{n-a}*f(2a-n))
      
    ​  总方案数是多少?可以理解为(g_{2n}),也可以理解为(f(n)),总之就是完全没有限制时的方案数。
      
    ​  有了(g)数组,就可以算出对于最大值为([n+1,2n-1])时的方案数,除以总方案数算出每个最大值出现的概率,最后就可以算出期望了。
        
      

    #include <cstdio>
    using namespace std;
    const int mod=1e9+7;
    const int N=500010;
    int n,f[N*2],g[N*2];
    inline int pow(int x,int y){
        int res=1;
        for(;y;x=1LL*x*x%mod,y>>=1)
            if(y&1) res=1LL*res*x%mod;
        return res;
    }
    int main(){
        scanf("%d",&n);
        f[0]=1;
        for(int i=2;i<=n;i+=2) f[i]=1LL*f[i-2]*(i-1)%mod;
        for(int v=n+1;v<=n*2;v++)
            g[v]=1LL*pow(v-n,n-v/2)*f[v/2-(n-v/2)]%mod;
        int ans=0;
        for(int v=n+1;v<=n*2;v++)
            (ans=ans+1LL*(g[v]-g[v-1])*v%mod)%=mod;
        ans=1LL*ans*pow(g[n*2],mod-2)%mod;
        printf("%d
    ",ans<0?ans+mod:ans);
        return 0;
    }
    
  • 相关阅读:
    MT【235】两道函数题
    MT【234】正方形染色(二)
    MT【233】染色正方形
    MT【232】展开式中的系数
    MT【231】棋子方法数
    MT【230】一道代数不等式
    MT【229】最小值函数
    MT【228】整数解的个数
    Python-list中的排序
    IO多路复用
  • 原文地址:https://www.cnblogs.com/RogerDTZ/p/8641362.html
Copyright © 2011-2022 走看看