CF Weakness and Poorness(三分查找+最大子段和)
https://codeforces.com/contest/578/problem/C


思路:因为要求做差连续子段和绝对值的最大,所以x的范围一定在[a_min,a_max]之间才会使结果尽可能小,同时我们可以发现这是一个单峰函数,先递减再递增,所以我们可以用三分查找算法来找峰值,然后我们可以通过最大子段和算法O(n)得到所有子段和中的最大值,负数就取最小子段和然后加绝对值就行了。
Code:
void solve()
{int n;cin>>n;vector<double> a(n),sum(n+1,0);for(auto &t:a) cin>>t;//求最大or最小子段和auto f=[&](double x)->double{int flag=0;double ans1=0,ans2=0;double ma=0;for(int i=0;i<n;i++){if(a[i]-x<0) flag=1;if(ans1+a[i]-x<0) ans1=0;else ans1+=a[i]-x;if(ans2+a[i]-x>0) ans2=0;else ans2+=a[i]-x;ma=max({ma,ans1,fabs(ans2)});}return ma;};double low=*min_element(a.begin(),a.end()),high=*max_element(a.begin(),a.end());while(high-low>4e-12)//1e-12会超时,把范围稍微缩小一点就可以了{double midl=low+(high-low)/3;double midr=high-(high-low)/3;if(f(midl)-f(midr)>4e-12) low=midl;else high=midr;}cout<<fixed<<setprecision(15)<<f(low);
}
