码迷,mamicode.com
首页 > 其他好文 > 详细

P1404 平均数

时间:2018-07-16 17:21:05      阅读:184      评论:0      收藏:0      [点我收藏+]

标签:++   接下来   getc   输出   char   记录   数据   长度   平均数   

题目描述

给一个长度为n的数列,我们需要找出该数列的一个子串,使得子串平均数最大化,并且子串长度>=m。

输入输出格式

输入格式:

 

N+1行,

第一行两个整数n和m

接下来n行,每行一个整数a[i],表示序列第i个数字

 

输出格式:

 

一个整数,他是最大平均数的1000倍,如果末尾有小数,直接舍去,不要用四舍五入求整。

 

输入输出样例

输入样例#1: 
10 6
6
4
2
10
3
8
5
9
4
1
输出样例#1: 
6500

说明

【数据范围】

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]),j\in[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 平均数

标签:++   接下来   getc   输出   char   记录   数据   长度   平均数   

原文地址:https://www.cnblogs.com/five20/p/9318473.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!