标签:二分 max int Ybtoj sum mid eps double 例题
解题思路
这道题显然需要二分一个平均值,
问题是小数怎么二分呢?
我们可以定义
l
,
r
,
m
i
d
l , r , m i d
l,r,mid 为
d
o
u
b
l
e
double
double类型,
并在判断时加上一个
e
p
s
eps
eps即可。(
e
p
s
eps
eps是在函数程序中事先声明的常量,是控制迭代精度的,相当于微积分里面的无限小值)
这个问题解决了,我们发现还有一个问题:
判断当前二分到的平均值是否满足条件是
O
(
n
2
)
O(n^2)
O(n2),会超时。
首先想到前缀和优化。
此时判断区间为
m
a
x
(
s
u
m
i
−
s
u
m
i
−
j
+
1
)
max(sum_i-sum_{i-j+1})
max(sumi−sumi−j+1)
(
l
<
i
≤
n
,
j
≤
i
−
l
)
(l<i≤n,j≤i−l)
(l<i≤n,j≤i−l)
不难发现 j 只会在
1
1
1~
i
−
l
i − l
i−l 中循环比较,直接 max 即可,可以省掉一个for循环。
然后注意让当前区间的
s
u
m
i
−
j
+
1
sum_{i-j+1}
sumi−j+1最小即可得到较优答案。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const double eps=1e-5;
int n,k;
double l,r,mid,sum[200000],a[200000];
bool check(double lyx)
{
for(int i=1;i<=n;i++)
sum[i]=sum[i-1]+a[i]-lyx;
double mann=2147483600,ans=-2147483600;
for(int i=k;i<=n;i++)
{
mann=min(mann,sum[i-k]);
ans=max(ans,sum[i]-mann);
}
if(ans>=0)return 1;
else return 0;
}
int main(){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
scanf("%lf",&a[i]);
l=-1e6,r=1e6;
while(l+eps<r)
{
mid=(l+r)/2;
if(check(mid))
l=mid;
else r=mid;
}
cout<<int(r*1000);
}
标签:二分,max,int,Ybtoj,sum,mid,eps,double,例题 来源: https://blog.csdn.net/kejin2019/article/details/112390460
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。