来自FallDream的博客,未经允许,请勿转载,谢谢。
n<=10^5
平均数最大的题目有一个经典的做法 就是二分答案 然后让所有数字减去那个答案 判断是否有大等于0的合法的一段即可
这道题显然可以开两个单调队列实现 然后二分的答案是实数,所以还要记一下是答案的区间。
复杂度nlogn
#include<iostream> #include<cstdio> #define MN 200000 #define INF 2000000000 #define ll long long #define ld double #define eps 1e-9 using namespace std; inline int read() { int x = 0 , f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} return x * f; } ll a[MN+5];int n,L,R,Ansl,Ansr; struct MyQue { int p[MN+5];ld s[MN+5];int top,tail; void clear(){top=0;tail=1;} void ins(int pos,ld y) { while(top>=tail&&y<s[top]) --top; p[++top]=pos;s[top]=y; } ld query(int pos) { while(top<tail&&p[tail]<pos) ++tail; if(top<tail) return INF+5; return s[tail]; } }Q,Q2; bool check(ld c) { Q.clear();Q2.clear(); for(int i=L;i<=n;++i) { ld th=(ld)a[i]-c*i; if((i-L)&1)Q.ins(i-L,(ld)a[i-L]-c*(i-L)); else Q2.ins(i-L,(ld)a[i-L]-c*(i-L)); if(th>=((i&1)?Q.query(i-R):Q2.query(i-R))) return Ansl=((i&1)?Q.p[Q.tail]:Q2.p[Q2.tail]),Ansr=i,true; } return false; } inline ll gcd(ll x,ll y){return !y?x:gcd(y,x%y);} int main() { n=read();L=read();R=read(); for(int i=1;i<=n;++i) a[i]=a[i+n]=read();n<<=1; ld l=0,r=INF,mid; for(int i=1;i<=n;++i) a[i]+=a[i-1]; for(int i=1;i<=100;++i) { mid=(l+r)/2.0; if(check(mid)) l=mid; else r=mid; } ll Ans=a[Ansr]-a[Ansl],F=Ansr-Ansl,g=gcd(Ans,F); Ans/=g;F/=g; if(F==1) printf("%lld",Ans); else printf("%lld/%lld ",Ans,F); return 0; }