UESTC488 組合計數

題意:

       長度爲n的非遞減序列,現已知其中m個位置上數的位置(一定知道首尾的數字),求還原該序列有多少種方案數,序列各位和的期望是多少?

分析:

      每兩個已知位置之間的問題相互獨立,

      則需要解決一個MIN>=A[I], MAX<=A[I+1]的非遞減序列有多少種方案,序列和的期望是多少?

      方案數:

      因爲N個數的非遞減排列數只有一種,即這是一個組合問題。

      可對應組合數學中“N種物品中選出K個,有多少種方案數”,C(N+K-1, N-1).

      注:該模型用隔板法理解,將這K個物品通過插入N-1個隔板分成N份,即在最終的N+K-1個位置中選N-1個放上隔板。

        期望:

      所有方案數中每個可選數的出現次數是相同的,即滿足A[I]到A[I+1]上的均勻分佈,每位上的期望爲(A[I]+A[I+1])/2;

      那K個位置的期望爲 k*(A[I]+A[I+1])/2;

        組合數計算:

        C(N,K)= N! / ( K! * ( N - K )! ),通過求逆元計算。

     當P爲素數時,a的逆元 = [ a ^ (p-2) ] % p


具體實現:    

     RE了一發,因爲沒有考慮組合數最大是N+K+1爲底的,開成了10^6

#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstring>
#include <cmath>
#include <set>
#include <vector>
#define mod 1000000009
using namespace std;
typedef long long LL;

LL a[2000],b[2000];
LL jc[2000100];

void init()
{
    jc[0]=1;
    for(int i=1;i<=2000010;i++)
        jc[i]=jc[i-1]*i%mod;
}

LL quick_pow(LL n,LL m)
{
    LL ans=1;
    while(m>0)
    {
        if(m&1)
            ans=(ans*n)%mod;
        n=(n*n)%mod;
        m>>=1;
    }
    return ans;
}

LL get_rev(LL n)
{
    return quick_pow(n,mod-2);
}

LL cal(LL n,LL m)
{
    return jc[n]*get_rev(jc[m])%mod*get_rev(jc[n-m])%mod;
}
int main()
{
    LL n,m;
    int T;
    init();
    scanf("%d",&T);
    for(int t=1;t<=T;t++)
    {
        scanf("%lld %lld",&n,&m);
        for(int i=0;i<m;i++)
            scanf("%lld",&a[i]);
        for(int i=0;i<m;i++)
            scanf("%lld",&b[i]);
        LL ca=1;
        double sum=0;
        for(int i=0;i<m-1;i++)
        {
            sum+=b[i];
            LL num=b[i+1]-b[i]+1;
            LL k=a[i+1]-a[i]-1;
            if(k==0) continue;
            ca=(ca*cal(num+k-1,min(k,n-1)))%mod;
            sum+=(double)k*(b[i]+b[i+1])/2;
        }
        sum+=b[m-1];
        printf("Case #%d: %lld %.3lf\n",t,ca,sum);
    }
    return 0;
}


  

發佈了52 篇原創文章 · 獲贊 9 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章