最佳牛围栏 及 寻找段落
作者:互联网
因其两题具有相似的地方因此合为一篇题解
-----题记
最佳牛围栏
思路:
二分答案
答案即为平均值
(小技巧:一般可以把序列都减去平均值,然后用前缀和),判断区间是否大于0,转化为判定性问题)
至少包含f块地,说明区间长度最少为f
每次减去平均值后,求出前缀和
if(sum[i]-min(sum[0]~sum[i-f])>0) return true;//如果成立此时区间平均值较小
- code
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int n,f;const int maxn=1e5+10;
int m[maxn];double sum[maxn];
bool check(double mid){
sum[0]=0;
for(int i=1;i<=n;++i) sum[i]=sum[i-1]+m[i]-mid;
double minv=0;
for(int i=0,j=f;j<=n;++i,++j){
minv=min(minv,sum[i]);
if(sum[j]>=minv) return true;
}
return false;
}
int main(){
scanf("%d%d",&n,&f);
for(int i=1;i<=n;++i) scanf("%d",&m[i]);
double l=0,r=2000;
while(r-l>1e-5){
double mid=(l+r)/2;
if(check(mid)) l=mid;
else r=mid;
}printf("%d",int(r*1000));
}
寻找最小线段
其实思路有上述大同小异
唯一的差别
就是区间 有上限
判断的时候
应该是这样
if(sum[i]-min(sum[i-t]~sum[i-s]) return 1;
维护一定区间的最小值可以考虑用到单调队列
bool cmp(double mid){
for(int i=s;i<=n;++i){
while(head<=tail && sum[q[tail]]>=sum[i-s]) --tail;//考虑sum[i-s]入队
q[++tail]=i-s;
while(head<=tail && q[head]<=i-t) ++head;//队头超出区间范围弹出
if(head<=tail && sum[i]-sum[q[head]]>0 ) return 1;//相减大于0说明平均值较小
}return 0;
}
ZFY AK IOI
标签:段落,return,平均值,最佳,int,double,sum,mid,围栏 来源: https://www.cnblogs.com/guiyou/p/15110706.html