Wannafly挑战赛3- A 珂朵莉

时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld

题目描述

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

输入描述:

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

输出描述:

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

AC code

求出 i 位置的断开的概率 pi ,那么答案就是 ans=ni=1pi
假设知道了 pi , 同时也可以知道这个位置之后最多连续有多少个元素和小于 x 的的元素个数 inum ,那么这位对 [i+1,i+2,,i+inum] 贡献 piinum
那么对于每一位

pi=k<ik+knumpkknum

尺取 O(n)

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>

const int MAXN = (int)1e5 + 5;

int a[MAXN], n, m, x;
double O[MAXN];

int main()
{
    scanf("%d%d", &n, &m);
    int ma = 0;
    for(int i = 1; i <= n; ++i) {
        scanf("%d", a + i);
        ma = std::max(ma, a[i]);
    }

    while(m--) {
        scanf("%d", &x);
        if(x < ma) puts("YNOI is good OI!");
        else {
            for(int i = 0; i <= n; ++i) O[i] = 0.0;

            int low = 1, top = 0, s = 0;
            double ans = 0.0, p = 0.0, pre_p = 1.0;
            while(low <= n) {
                if(s <= x && top <= n) {
                    s += a[++top];
                } else {
                    double t = pre_p / (top - low);
                    O[top] -= t;
                    s -= a[low];
                    p += O[low++] + t;
                    ans += pre_p = p;
                }
            }
            printf("%.2lf\n", ans);
        }
    }
    return 0;
}

输入

5 6
1 2 3 4 5
4
5
6
7
8
9

输出

YNOI is good OI!
4.25
3.83
3.58
3.58
3.11

说明

对于30%的数据,n , m <= 10
对于60%的数据,n <= 1000 , m <= 10
对于80%的数据,n <= 100000 , m <= 100
对于100%的数据,n <= 100000 , m <= 500 , 0 <= a[i] <= 1000 , x <= 1000000
PS:数据直接随的,不知道有没有乱搞方法~

猜你喜欢

转载自blog.csdn.net/ctsas/article/details/78503928