UVALive 8138-Number Generator【概率DP】

題意:隨機的給你k個數,範圍1~n,問你使得區間[1, n]的每個數都出現至少兩次的期望次數。

思路:f[i][j] 表示有i個數需要出現一次,j個數需要出現兩次,那麼:

f[i][j] = i / n * f[i - 1][j] + j / n * f[i + 1][j - 1] + (n - i - j) / n * f[i][j] + 1

f[i][j] = i / (i + j) * f[i - 1][j] + j / (i + j) * f[i + 1][j - 1] + n / (i + j)

這題多樣例要記憶化一下否則會超時,但是n不同會導致結果不同,所以把n提出來

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 3e3 + 10;
double f[maxn][maxn];
int vis[maxn];
int n;

double calc(int i, int j)
{
    if(i == 0 && j == 0) return 0;
    if(f[i][j]) return f[i][j];
    f[i][j] = 1;
    if(i > 0) f[i][j] += i  * calc(i - 1, j);
    if(j > 0) f[i][j] += j  * calc(i + 1, j - 1);
    f[i][j] = f[i][j] / (i + j);
    return f[i][j];
}

int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        memset(vis, 0, sizeof(vis));
        int k, x;
        scanf("%d%d", &n, &k);
        for(int i = 1; i <= k; ++i) scanf("%d", &x), vis[x]++;
        int cnt1 = 0, cnt2 = 0;
        for(int i = 1; i <= n; ++i)
        {
            if(vis[i] == 1) cnt1++;
            else if(vis[i] == 0) cnt2++;
        }
        printf("%.10f\n", n * calc(cnt1, cnt2));
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章