题外话:我的实数二分有什么问题=。=
仍然(我为什么要这么说)是二分答案,如何检查呢?将所有的数减去二分出来的$mid$后求和得到和$sum$,然后如果在减出来的数列中能找出一段大于$sum$的数则可行。推式子
在减去二分出的$mid$之后,设切掉$[l,r]$,数列的总和为$tot$
$sum[1,l-1]+sum[r+1,n]+sum[l,r]=tot-mid*n$
$sum[1,l-1]+sum[r+1,n]=tot-mid*n-sum[l,r]$
只要最大化$sum[l,r]$使得剩下的和小于等于零即可,找最大子段和,注意题目强制我们选至少一个
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=100005; 6 const double eps=1e-7; 7 double num[N],tmp[N]; 8 double l,r,ans; int n; 9 bool check(double x) 10 { 11 double tep=0.0,sum=0.0,maxx=-1e9; 12 for(int i=1;i<=n;i++) 13 tmp[i]=num[i]-x,tep+=tmp[i]; 14 for(int i=2;i<n;i++) 15 sum+=tmp[i],maxx=max(maxx,sum),sum=max(sum,0.0); 16 return tep-maxx<=eps; 17 } 18 int main () 19 { 20 scanf("%d",&n); 21 for(int i=1;i<=n;i++) 22 scanf("%lf",&num[i]),r=max(r,num[i]); 23 while(r-l>=eps) 24 { 25 double mid=(l+r)/2; 26 if(check(mid)) r=mid; else l=mid; 27 } 28 printf("%.3lf",r); 29 return 0; 30 }