时间限制: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
, 同时也可以知道这个位置之后最多连续有多少个元素和小于
x
的的元素个数
那么对于每一位
尺取 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:数据直接随的,不知道有没有乱搞方法~