Wannafly挑战赛3-A.珂学送分(概率方程+后缀和)

A 珂学送分(概率)

给你一个长 n 的序列,m 次查询每次查询给一个 x,然后:从序列的最左端 1 开始,每次随机的选择一个右端点 r,如果两个端点间的区间和不超过 x ,就进行一次分割,然后把左端点变成 r + 1, 否则一直随机下去。问这样分割出来的期望段数

思路:假设 f(x)[xn] ,假设x的分割极限最右是y,那么显然可以得到 f(n)=yi=x+1f(i) 。那么我们可以倒过来递推这个递推式,用一个后缀和维护一下即可。

#include <bits/stdc++.h>
using namespace std;

const int maxn = 100000 + 5;
int a[maxn], maxJ[maxn];
double f[maxn],  suffixSum[maxn];

int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    for(int i = 0; i < n; i++) scanf("%d", &a[i]);

    for(int i = 0; i < m; i++)
    {
        int x;
        scanf("%d", &x);
        if(x < *max_element(a, a + n))
        {
            puts("YNOI is good OI!");
            continue;
        }
        int mx = 0, sum = 0, p = 0;
        for(int i = 0; i < n; i++)
        {
            while(p < n && sum + a[p] <= x) sum += a[p], p++;
            maxJ[i] = max(i, p);
            sum -= a[i];
        }
        f[n - 1] = suffixSum[n - 1] = 1;
        for(int i = n - 2; i >= 0; i--)
        {
            int lb = i, rb = maxJ[i];
            f[lb] = (suffixSum[lb + 1] - suffixSum[rb + 1]) / (rb - lb) + 1;
            suffixSum[i] = suffixSum[i + 1] + f[i];
        }
        printf("%.2f\n", f[0]);
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_29556211/article/details/78550276