1. 程式人生 > >【CodeForces】578 C. Weakness and Poorness

【CodeForces】578 C. Weakness and Poorness

const 現在 else log display closed string force bit

【題目】C. Weakness and Poorness

【題意】給定含n個整數的序列ai,定義新序列為ai-x,要使新序列的最大子段和絕對值最小,求實數x。n<=2*10^5。

【算法】二分||三分||計算幾何(凸包)

【題解】Editorial

令正數最大子段和為A,負數最大子段和為B,絕對值是max(A,B)。當x從小到大變化時,A由大變小,B由小變大。

容易發現這是一個下凸函數,可以用三分法求解。

但是,這道題卡精度(-11會WA,-12會T),解決方法是根據復雜度把循環次數卡到極限而不用r-l<=eps的方法,以及縮小一開始的l和r範圍防卡。

技術分享圖片
#include<cstdio>
#include
<cstring> #include<cctype> #include<cmath> #include<queue> #include<stack> #include<set> #include<vector> #include<algorithm> #define ll long long #define lowbit(x) x&-x using namespace std; int read(){ char c;int s=0,t=1; while(!isdigit(c=getchar()))if
(c==-)t=-1; do{s=s*10+c-0;}while(isdigit(c=getchar())); return s*t; } int ab(int x){return x>0?x:-x;} //int MO(int x){return x>=MOD?x-MOD:x;} //void insert(int u,int v){tot++;e[tot].v=v;e[tot].from=first[u];first[u]=tot;} /*------------------------------------------------------------*/ const
int maxn=200010; const double eps=1e-9; int n; double a[maxn],b[maxn]; double F(double x){ for(int i=1;i<=n;i++)b[i]=a[i]-x; double sum=0,ans=0; for(int i=1;i<=n;i++){ sum+=b[i]; if(sum<0)sum=0; ans=max(ans,sum); } sum=0; for(int i=1;i<=n;i++){ sum+=b[i]; if(sum>0)sum=0; ans=max(ans,-sum); } return ans; } int main(){ n=read(); double m1,m2,l=-10010,r=10010; for(int i=1;i<=n;i++)scanf("%lf",&a[i]); for(int i=1;i<=100;i++){ m1=l+(r-l)/3;m2=l+(r-l)/3*2; if(F(m1)<F(m2))r=m2;else l=m1; } printf("%.10lf",F(l)); return 0; }
View Code

進一步觀察,發現答案出現在A=B時,當x偏小時A>B,當x偏大時A<B,那麽可以二分求解。

最後的幾何解法,將max(si-sj)展開後化為以x為自變量,y為絕對值的一些直線,然後求上下凸包。

【CodeForces】578 C. Weakness and Poorness