• BZOJ5090 组题 BZOJ2017年11月月赛 二分答案 单调队列


    欢迎访问~原文出处——博客园-zhouzhendong

    去博客园看该题解


    题目传送门 - BZOJ5090 11月月赛A题


    题意概括

      给出n个数。

      求连续区间(长度大于等于k)最大平均值。


    题解

      这题大概不是原题。

      很简单的题目(对于大佬而不对于我来说),做过一次。

      具体做法:

      首先二分答案平均值(最好用long double保证精度)

      然后根据前缀和来单调队列判断。

      假设当前要判断的答案为x。

      我们把原序列的每一个数都减去x。

      那么前缀和数组的第i个就减掉了i*x

      那么我得到了一个新的前缀和数组(long double型)。

      如果原序列存在平均值大于x的,那么修改后的序列必然存在总和大于等于0的连续一段数(当然长度要大于或等于k)

      那么只需要看是否有距离>=k的两个前缀和的值满足前面一个小于后面一个就可以了。

      这个可以用单调队列维护解决。

      剩下的就是答案及细节处理。注意开longlong


    代码

    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    using namespace std;
    typedef long long LL;
    typedef long double LD;
    const int N=100005;
    const LD Eps=1e-9;
    int n,k,ansL,ansR;
    int q[N],head,tail;
    LL sum[N],A,B;
    LD val[N];
    LL gcd(LL a,LL b){
    	return b?gcd(b,a%b):a;
    }
    bool check(LD x){
    	for (int i=0;i<=n;i++)
    		val[i]=-x*i+sum[i];
    	head=1,tail=0;
    	for (int i=k;i<=n;i++){
    		while (head<=tail&&val[i-k]<val[q[tail]])
    			tail--;
    		q[++tail]=i-k;
    		if (head<=tail&&val[q[head]]<val[i]){
    			ansL=q[head],ansR=i;
    			return 1;
    		}
    	}
    	return 0;
    }
    int main(){
    	scanf("%d%d",&n,&k);
    	sum[0]=0;
    	for (int i=1;i<=n;i++)
    		scanf("%lld",&sum[i]),sum[i]+=sum[i-1];
    	LD L=-1e8,R=1e8,M;
    	while (R-L>Eps){
    		M=(R+L)*0.5;
    		if (check(M))
    			L=M;
    		else
    			R=M;
    	}
    	A=sum[ansR]-sum[ansL];
    	B=ansR-ansL;
    	LL g=gcd(A,B);
    	A/=g,B/=g;
    	if (B<0)
    		A=-A,B=-B;
    	printf("%lld/%lld",A,B);
    	return 0;
    }
    

      

  • 相关阅读:
    SqlHelper
    asp.net中窗口相关操作总结(javascript)
    ASP.NET顯示對話框
    为ASP.NET控件添加常用的JavaScript操作
    右键弹出菜单
    log4net的初使用
    QQ/MSN右下角弹出提示窗口
    简便无刷新文件上传系统
    简单的自动更新程序实
    SQL中的单记录函数
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/BZOJ5090.html
Copyright © 2020-2023  润新知