ICPC 焦作 Sequence

ICPC 焦作 Sequence

https://nanti.jisuanke.com/t/31713

題目是給定 1<m<250,1<n<109

[1,n] 中等概率取m 個數字,組成一個非遞減序列,記f(i)i 出現的次數 .

計算下式期望
maxi=1nf(i)

顯然,順序不重要,考慮計算所有可能的總情況的數量,即方程:

f(1)+f(2)+f(3)+...+f(n)=m

對應的總答案數。

這個方程答案數量爲(對m個1進行插入n-1個擋板,擋板之間的1的個數對應f):
(n+m1m)

dp[m][x][t] 爲將m 拆分成t 個數字,最大數字爲x 的所有排列。

那麼我們將這t 個數隨機分配給f ,未分配的f 的是0 ,那麼分配方案顯然是:
(nt)

記:P(x)maxi=1n f(i)=x 的概率。

P(x)=t=1mdp[m][x][t](nt)(n+m1m)

下面考慮計算dp 數組。

顯然,dp[m][x][t] 可以分兩部貢獻:

第一部分,最後一個數字拆分小於x,那麼之後的拆分必須出現一個x:
k=1x1dp[nk][x][t1]

A[m][x][t] 表示拆分最大數字不超過x 的所有排列:

那麼第二部分貢獻爲:
A[mx][x][t1]

對於A[m][x][t] 有:
A[m][x][t]=k=1xA[mk][x][t1]

考慮壓縮t ,並遞推過程中記錄。B[x][t]=dp[m][x][t]

這樣就有了概率密度函數。

則答案爲:
ans=x=1mxP(x)=x=1mxt=1mB[x][t](nt)(n+m1m)

#include <stdio.h>
#include <algorithm>
#include <string.h>
#define MAXN  252
using namespace std;

long double C;
double dp[MAXN][MAXN][2];
double Sd[MAXN][MAXN][2];
double Sa[MAXN][MAXN][2];
double A[MAXN][MAXN][2];
double B[MAXN][MAXN];
int main()
{
    int n, m;
    while (scanf("%d %d", &m, &n) == 2)
    {
        memset(dp, 0, sizeof dp);
        memset(Sa, 0, sizeof Sa);
        memset(Sd, 0, sizeof Sd);
        memset(A, 0, sizeof A);
        memset(B, 0, sizeof B);
        for (int i = 0;i <= m;i++)A[0][i][0] = 1;
        for (int i = 0;i <= m;i++)
            for (int j = 0;j <= m;j++)Sa[i][j][0] = 1;
        for (int i = 0;i <= m;i++)Sd[i][0][0] = 1;
        dp[0][0][0] = 1;
        bool ansf = false;
        for (int t = 1;t <= m;t++, ansf = !ansf)
        {
            for (int x = 0;x <= m;x++)A[0][x][!ansf] = 0;
            for (int i = 0;i <= m;i++)
                for (int x = 0;x <= m;x++)Sd[i][x][!ansf] = Sa[i][x][!ansf] = 0;
            for (int i = 1;i <= m;i++)
            {
                for (int x = 1;x <=m;x++)
                {
                    if (x > i)
                    {
                        dp[i][x][!ansf] = 0;
                        A[i][x][!ansf] = A[i][i][!ansf];
                        Sa[i][x][!ansf] = Sa[i - 1][x][!ansf] + A[i][x][!ansf];
                        Sd[i][x][!ansf] = Sd[i - 1][x][!ansf];
                        continue;
                    }
                    A[i][x][!ansf] = Sa[i - 1][x][ansf];
                    if (i > x)A[i][x][!ansf] -= Sa[i - x - 1][x][ansf];
                    dp[i][x][!ansf] = A[i - x][x][ansf] + Sd[i - 1][x][ansf] - Sd[i - x][x][ansf];
                    Sd[i][x][!ansf] = Sd[i - 1][x][!ansf] + dp[i][x][!ansf];
                    Sa[i][x][!ansf] = Sa[i - 1][x][!ansf] + A[i][x][!ansf];
                }
                if (i == m)
                    for (int x = 1;x <= m;x++)  B[x][t] = dp[m][x][!ansf];
            }
        }
        C = 1;
        long double ans = 0;
        for (int k = 1;k <= m;k++)C *= ((long double)k) / ((long double)n - 1 + k);
        for (int t = 1;t <= m&&t <= n;t++)
        {
            C *= (long double)(n - t + 1) / (long double)t;
            for (int x = 1;x <= m;x++)
            {
                //if (B[x][t])printf("%lld\n", B[x][t]);
                ans += x*B[x][t] * C;
            }
        }
        printf("%.4f\n", (double)ans);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章