2019.2.15 t3 平均值
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #include <cmath> 5 #include <cctype> 6 #include <cstring> 7 #include <queue> 8 #include <algorithm> 9 using namespace std; 10 11 #define res register int 12 inline int read() 13 { 14 int x(0),f(1); char ch; 15 while(!isdigit(ch=getchar())) if(ch=='-') f=-1; 16 while(isdigit(ch)) x=x*10+ch-'0',ch=getchar(); 17 return f*x; 18 } 19 20 inline int max(int x,int y){return x>y?x:y;} 21 inline double max(double x,double y){return x>y?x:y;} 22 inline int min(int x,int y){return x<y?x:y;} 23 24 const int N=50000+5; 25 int a[N],n,k,L,R,t; 26 int d[N],q[N],q1[N]; 27 double s[N];//差分数组,前缀和数组 28 29 inline bool check(double m) 30 { 31 int l=1,r=0; //把i看成右端点(此处取得最大s),找s[i]最小的左端点 32 double ans(-1e9-7); 33 for(res i=1 ; i<=n ; i++) 34 { 35 if(i-L+1<=0) continue; 36 while(l<=r && s[q[r]]>=s[i-L+1]) r--; 37 //加入i-L+1(和之前比右端点向右挪了一位) 38 q[++r]=i-L+1; 39 while(i-q[l]+1>R && l <= r) l++;//排除非法 40 if(l<=r) ans=max(ans,s[i]-s[q[l]]); 41 } 42 return ans>m*k; 43 } 44 45 inline bool judge(double m) 46 { 47 for(res i=1 ; i<=n ; i++) 48 s[i]=s[i-1]+(double)d[i]-m; 49 return check(m); 50 } 51 int main() 52 { 53 freopen("average.in","r",stdin); 54 freopen("average.out","w",stdout); 55 int T=read(); 56 while(T--) 57 { 58 double maxn(0.0); 59 n=read(); k=read(); L=read(); R=read(); 60 for(res i=1 ; i<=n ; i++) a[i]=read(); 61 for(res i=1 ; i<=n ; i++) d[i]=a[i]-a[i-1]; 62 double l=0,r=1e9+7; 63 int head(1),tail(0),head1(1),tail1(0); 64 double ans(-100000000.0); 65 //特殊情况,取得最大值与最小值的两端点之间的距离小于L 66 //此处用线段树也可以 67 for(res i=1 ; i<=n ; i++) 68 { 69 while((head<=tail) && (a[q[tail]]>a[i])) tail--; 70 q[++tail]=i; 71 while((head1<=tail1) && (a[q1[tail1]]<a[i])) tail1--; 72 q1[++tail1]=i; 73 while((head<=tail) && i-q[head]+1 > L) head++; 74 while((head1<=tail1) &&i-q1[head1]+1 > L) head1++; 75 ans=max(ans,(double)(a[q1[head1]]-a[q[head]]) / (double)(L+k-1)); 76 } 77 while(r-l>0.0000001) 78 { 79 double mid=(l+r)/2; 80 if(judge(mid)) l=mid,ans=max(ans,l); 81 else r=mid; 82 } 83 //翻转过来,再求一遍,即在刚才的右端点处取得最小s 84 reverse(a+1,a+n+1); 85 for(res i=1 ; i<=n ; i++) d[i]=a[i]-a[i-1]; 86 l=0,r=1e9+7; 87 while(r-l>0.0000001) 88 { 89 double mid=(l+r)/2.0; 90 if(judge(mid)) l=mid,ans=max(ans,l); 91 else r=mid; 92 } 93 printf("%.4lf\n",ans); 94 } 95 return 0; 96 }