题解 CF578C 【Weakness and Poorness】

swiftc

2019-06-26 18:56:42

Solution

#### 我感觉这道题还是三分做比较好吧 首先看到题面,设check(x)为a1-x,a2-x,...,an-x的不美好程度 显然它不是单调的,所以我们用三分来解 三分大家都会吧,那么我们来考虑check(x)怎么求 ### 1.暴力求法 直接求出前缀和,然后暴力模拟 代码: ```cpp //fabs为double的abs double check(double s){ double ans=-1.0; for(int i=1;i<=n;i++){ a[i]-=s; } double tmp[200001]; memset(tmp,0,sizeof(tmp)); for(int i=1;i<=n;i++){ tmp[i]=a[i]+tmp[i-1]; } for(int i=1;i<=n;i++){ for(int j=1;j<=i;j++){ ans=max(ans,fabs(tmp[i]-tmp[j-1])); } } for(int i=1;i<=n;i++){ a[i]+=s; } return ans; } ``` 可以过7个点 ![](https://cdn.luogu.com.cn/upload/pic/61446.png) ### 2.正解 让我们先求出一个前缀和数组tmp 让我们想一想,可不可以不用对于每一个i都从1~i-1枚举j呢? 因为我们要求最大的fabs(tmp[i]-tmp[j]),所以我们只需要tmp[1]~tmp[i-1]中的最大值和最小值 对于剩下的tmp[j]不可能使答案变的更大 代码: ```cpp inline double check(double x){ double sum=0,ret=0,Min=0,Max=0; for(int i=1;i<=n;i++) { sum+=a[i]-x; //因为我们只需要当前的前缀和,所以我们只保留当前的前缀和即可,不需要求tmp数组 ret=max(ret,fabs(sum-Min)); ret=max(ret,fabs(sum-Max)); //更新数列的不美好程度 Min=min(Min,sum); Max=max(Max,sum); //更新前缀和的最大值和最小值 } return ret; } ``` 完整代码: 注意:一定要注意精度 ~~while(r-l>=xxx)这种我没调出来~~ ```cpp #ifdef DEBUG #include"stdc++.h" #else #include<bits/stdc++.h> #endif using namespace std; int n; double a[200001]; inline double check(double x){ double sum=0,ret=0,Min=0,Max=0; for(int i=1;i<=n;i++) { sum+=a[i]-x; ret=max(ret,fabs(sum-Min)); ret=max(ret,fabs(sum-Max)); Min=min(Min,sum); Max=max(Max,sum); } return ret; } int main(){ scanf("%d",&n); double l=0,r; for(int i=1;i<=n;i++)scanf("%lf",&a[i]); for(int i=1;i<=n;i++){ l=min(l,-fabs(a[i])); } r=-l; int cnt=0; while(cnt++<400){ double m1=l+(r-l)/3,m2=r-(r-l)/3; double a1=check(m1),a2=check(m2); if(a1<a2){ r=m2; } else{ l=m1; } } printf("%.6lf\n",check((l+r)/2.0)); return 0; } ```