Best Cow Fences POJ - 2018
考察:二分
再做一次还是没想到系列 蒟蒻本蒻
思路:
这道题的check函数很好想,就是枚举端点,找到区间>=l&&平均值>=mid的区间.暴力枚举是sum[j]-sum[i]>=(j-i)*mid.我们需要进行优化,要将二重循环优化到一维,i必须省去,我们求[i,j]区间是否平均值>=mid,转化为sum[i,j]-(j-i)*mid>=0,而这相当于在[i,j]区间内每个元素都-=mid,最后看是否>=0.省去(j-i)*mid,我们还要考虑如何优化掉sum[i],可以发现随着右端点不断延伸,左端点可取值是连续增加的(如果枚举左端点就是不断减少),根据此性质可以动态求出最小值,只要看sum[j]-mins>=0即可.
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 using namespace std; 6 typedef long long LL; 7 const int N = 100010; 8 const double eps = 1e-5; 9 int n,f,maxn,a[N]; 10 double b[N]; 11 bool check(double s) 12 { 13 for(int i=1;i<=n;i++) b[i] = a[i]-s,b[i]+=b[i-1]; 14 double tmp = 0; 15 for(int i=f,j=0;i<=n;i++) 16 { 17 tmp = min(tmp,b[j]),j++; 18 if(b[i]-tmp>=0) return 1; 19 } 20 return 0; 21 } 22 int main() 23 { 24 scanf("%d%d",&n,&f); 25 for(int i=1;i<=n;i++) scanf("%d",&a[i]),maxn = max(maxn,a[i]); 26 double l = 0,r = maxn; 27 while(r-l>eps) 28 { 29 double mid = (r+l)/2; 30 if(check(mid)) l = mid; 31 else r = mid; 32 } 33 int ans = r*1000; 34 printf("%d\n",ans); 35 return 0; 36 }
2021.6.23 大草,再做一次还是没做出来,前缀和数组没有递增或递减的性质,没想出来怎么求>=f的区间的最大差是否>=0.这里的骚操作是求左端点区间内的最小值.没想到啊我太菜了.