P1404 平均数
Posted five20
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P1404 平均数相关的知识,希望对你有一定的参考价值。
题目描述
给一个长度为n的数列,我们需要找出该数列的一个子串,使得子串平均数最大化,并且子串长度>=m。
输入输出格式
输入格式:
N+1行,
第一行两个整数n和m
接下来n行,每行一个整数a[i],表示序列第i个数字
输出格式:
一个整数,他是最大平均数的1000倍,如果末尾有小数,直接舍去,不要用四舍五入求整。
输入输出样例
说明
【数据范围】
60% M<=N<=10000
100% M<=N<=100000 0<=a[i]<=2000
Solution:
经典的二分答案问题。
直接二分平均值,然后验证。
验证时的思路是分数规划+前缀和,每个数都减去二分的值$mid$,并求出前缀和,问题转化为是否存在一个长度不小于$m$的子串使得其和大于等于$0$。显然子串右端点$i$范围为$[m,n]$,左端点$j$属于$[1,i-m+1]$,每次我们没有必要去枚举左端点,当右端点确定后,等价于判断$sum[i]-min(sum[j-1]),jin[1,i-m+1]$是否大于等于$0$,而每次$i$的右移一位只会使得$j$的最大值右移一位,那么我们直接记录一下可以选的左端点最小值就好了,然后就能$O(n)$扫一遍验证。
代码:
1 #include<bits/stdc++.h> 2 #define il inline 3 #define ll long long 4 #define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) 5 #define Bor(i,a,b) for(int (i)=(b);(i)>=(a);(i)--) 6 using namespace std; 7 const int N=100005; 8 int n,m; 9 double a[N],b[N],s[N]; 10 11 il int gi(){ 12 int a=0;char x=getchar();bool f=0; 13 while((x<‘0‘||x>‘9‘)&&x!=‘-‘)x=getchar(); 14 if(x==‘-‘)x=getchar(),f=1; 15 while(x>=‘0‘&&x<=‘9‘)a=(a<<3)+(a<<1)+x-48,x=getchar(); 16 return f?-a:a; 17 } 18 19 int main(){ 20 n=gi(),m=gi(); 21 For(i,1,n) a[i]=gi(); 22 double l=0,r=2005,mid; 23 while(r-l>1e-5){ 24 mid=(l+r)/2; 25 For(i,1,n) b[i]=a[i]-mid,s[i]=s[i-1]+b[i]; 26 double minn=1e10,ans=-1e10; 27 For(i,m,n) minn=min(minn,s[i-m]),ans=max(ans,s[i]-minn); 28 (ans>=0)?(l=mid):(r=mid); 29 } 30 cout<<(int)(r*1000); 31 return 0; 32 }
以上是关于P1404 平均数的主要内容,如果未能解决你的问题,请参考以下文章
Java8 Stream针对List先分组再求和最大值最小值平均值等