2 条题解

  • 1
    @ 2022-8-25 10:11:43
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int maxn = 5e5+10;
    const double eps = 1e-6;
    double a[maxn];
    double c[maxn];
    int head1,head2,tail1,tail2;
    int q1[maxn],q2[maxn];
    int n,k,L,R;
    int q3[maxn];
    inline int read(){//快读
    	int s = 0,f = 1;
    	char ch = getchar();
    	while(ch < '0' || ch > '9'){
    		if(ch == '-')f = -1;
    		ch = getchar();
    	}
    	while(ch >= '0' && ch <= '9'){
    		s = s * 10 + ch - '0';
    		ch = getchar();
    	}
    	return s * f;
    }
    bool jud(double mid){//二分判断函数
    	memset(c,0,sizeof(c));
    	for(int i=1;i<=n;++i){//记录第一种相减的情况
    		c[i] = a[i] - i * mid;
    	}
    	double ans = -100000.0;
    	int head3=0,tail3=0;
    	for(int i=L+1;i<=n;++i){//单调队列维护最大值
    		while(head3 < tail3 && i - q3[head3] >= R)head3++;
    		while(head3 < tail3 && c[q3[tail3-1]] >= c[i-L])tail3--;
    		q3[tail3++] = i-L;//记录最小值的位置
    		ans = max(ans,c[i] - c[q3[head3]]);
    	}
    	head3=0,tail3=0;
    	for(int i=1;i<=n;++i){//找另一种相加的情况
    		c[i] = a[i] + i * mid;
    	}
    	for(int i=n-L;i;--i){//单调队列维护最大值
    		while(head3 < tail3 && i - q3[head3] >= R)head3++;
    		while(head3 < tail3 && c[q3[tail3-1]] >= c[i+L])tail3--;
    		q3[tail3++] = i+L;
    		ans = max(ans,c[i] - c[q3[head3]]);
    	}
    	return ans - mid * k >= 0;//判断是否成立
    }
    double calc1(){//计算长度为L的情况下的答案
    	double ans = -100000.0;
    	head1 = head2 = tail1 = tail2 = 0;//一定要初始化,不然爆掉
    	for(int i=1;i<=n;++i){
    		if(i < L){//位置不超过L的时候只维护单调性
    			while(head1 < tail1 && a[q1[tail1-1]] >= a[i])tail1--;
    			while(head2 < tail2 && a[q2[tail2-1]] <= a[i])tail2--;
    		}
    		else {//位置超过L的时候维护单调性且长度超过L的时候弹出队首
    			while(head1 < tail1 && i - q1[head1] >= L)head1++;
    			while(head2 < tail2 && i - q2[head2] >= L)head2++;
    			while(head1 < tail1 && a[q1[tail1-1]] >= a[i])tail1--;
    			while(head2 < tail2 && a[q2[tail2-1]] <= a[i])tail2--;
    		}
    		q1[tail1++] = i;
    		q2[tail2++] = i;
    		if(i >= L)//算答案
    			ans = max(ans,(double)(a[q2[head2]] - a[q1[head1]]) / (L-1+k));
    	}
    	return ans;
    }
    int main(){
    	int T = read();
    	while(T--){
    		n = read();
    		k = read();
    		L = read();
    		R = read();
    		for(int i=1;i<=n;++i){
    			scanf("%lf",&a[i]);
    		}
    		double ans = calc1();//长度刚好为L的答案
    		double l = 0,r = 1000000.0;
    		while(r - l >= eps){//二分找到最优解
    			double mid = (l + r) / 2;
    			if(jud(mid))l = mid;
    			else r = mid;
    		}
    		printf("%.4lf\n",max(ans,l));//取两种情况的最大值
    	}
    	return 0;
    }
    
    • 0
      @ 2022-8-3 7:30:25

      定义

      $$w(l,r)=\max\{a_k|l\le k\le r\}-\min\{a_k|l\le k\le r\} $$

      则易证 w(l,r)w(l,r) 满足区间包含单调性。(即,[a,b][c,d]w(a,b)w(c,d)[a,b]\sube[c,d]\Rightarrow w(a,b)\le w(c,d)

      定义

      W(l,r)=aralW(l,r)=|a_r-a_l|

      则易证 w(l,r)=max{w(l,r1),w(l+1,r),W(l,r)}w(l,r)=\max\{w(l,r-1),w(l+1,r),W(l,r)\}

      定义

      wm=max{w(l,r)rl+1=m}w_m=\max\{w(l,r)|r-l+1=m\} Wm=max{W(l,r)rl+1=m}W_m=\max\{W(l,r)|r-l+1=m\}

      则易证 wm=max{wm1,Wm}w_m=\max\{w_{m-1},W_m\}

      我们现在要求

      $$\max\{\frac{w_m}{m-1+K}|L\le m\le R\} \\= \max\{\max\{\frac{W_m}{m-1+K}|L\le m\le R\},\frac1{L-1+K}\max\{W_m|1\le m<L\}\} $$

      对于第二类贡献,我们可以一次扫描线 + 单调队列解决。

      考虑 max{Wmm1+KLmR}\max\{\frac{W_m}{m-1+K}|L\le m\le R\} 的贡献。

      考虑二分答案。

      设要 check 是否有 max{Wmm1+KLmR}x\max\{\frac{W_m}{m-1+K}|L\le m\le R\}\ge x

      即是否有

      max{Wm(m1)xLmR}xK\max\{W_m-(m-1)x|L\le m\le R\}\ge xK

      即是否有

      $\max\{\max\{(a_l+lx)-(a_r+rx),(a_r-rx)-(a_l-lx)\}|L\le r-l+1\le R\}\ge xK$。

      即是否有

      $\max\{b_l-b_r|L\le r-l+1\le R\}\ge V\lor\max\{c_r-c_l|L\le r-l+1\le R\}\ge V$。

      这个可以单轮 O(n)O(n) 解决。

      众所周知单调队列狗都不写,因此我们单调队列真香。

      总复杂度 O(nlogv)O(n\log v)

      • 1

      信息

      ID
      4476
      时间
      1000ms
      内存
      256MiB
      难度
      7
      标签
      (无)
      递交数
      42
      已通过
      9
      上传者