A 珂学送分(概率)
给你一个长 n 的序列,m 次查询每次查询给一个 x,然后:从序列的最左端 1 开始,每次随机的选择一个右端点 r,如果两个端点间的区间和不超过 x ,就进行一次分割,然后把左端点变成 r + 1, 否则一直随机下去。问这样分割出来的期望段数
思路:假设
#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;
}