解题:USACO14MAR Sabotage

题面

题外话:我的实数二分有什么问题=。=

仍然(我为什么要这么说)是二分答案,如何检查呢?将所有的数减去二分出来的$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
 2 #include
 3 #include
 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)
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 }
View Code

 

转载于:https://www.cnblogs.com/ydnhaha/p/9677974.html

你可能感兴趣的:(解题:USACO14MAR Sabotage)