Wannafly挑战赛A(概率DP)

#include <bits/stdc++.h>

using namespace std;
const int N = 1E5 + 7;
double f[N], sf[N];
int sa[N], a[N];
int main()
{
    int n, m, mx=0, x;
    scanf("%d%d",&n,&m);
    for(int i = 1;i <= n;i ++) {
        scanf("%d",&a[i]);
        mx = max(mx, a[i]);
    }
    for(int i = n;i >= 1;i --) sa[i] += sa[i + 1] + a[i];
    while(m --) {
        scanf("%d",&x);
        if(mx > x) {
            puts("YNOI is good OI!");
        } else {
            int j = n;
            for(int i = n;i >= 1;i --) {
                while(sa[i] - sa[j + 1] > x) j --;
                double len = j - i + 1;
                f[i] = (sf[i+1] - sf[j+2]) / len + 1;
                sf[i] = sf[i + 1] + f[i];
            }
            printf("%.2f\n",f[1]);
        }
    }
    return 0;
}

题目描述

给你一个长 n 的序列,m 次查询

每次查询给一个 x,然后:

从序列的最左端 1 开始,每次随机的选择一个右端点 r,如果两个端点间的区间和不超过 x ,就进行一次分割,然后把左端点变成 r + 1, 否则一直随机下去。

问这样分割出来的期望段数

输入描述:

第一行两个数 n,m
之后一行 n 个数表示这个序列
之后m行每行一个数 x,表示求每段的和不大于 x 的情况下切割的期望段数

输出描述:

m 行,每行一个保留到小数点后2位的数表示答案
如果无论如何都没有合法的切割方案,输出"YNOI is good OI!",不含引号


题解:很少的概率DP,从后往前,需要用 f[i]表示[i..n]这段子序列可以切成的期望段数,对于每个i,我们可以找到一个最大的j,使得[i..j]这段和小于X,那么
f[i] = sigma(i+1,j+1)f[k] / len + 1;维护一个后缀sf[i] = sigma[i..n]f[k];和一个单调指针
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值