zoukankan      html  css  js  c++  java
  • 【JZOJ4256】平均数【二分】

    题目大意:

    题目链接:https://jzoj.net/senior/#main/show/4256
    给出包含一个NN个整数的数组AA。找出一段长度至少为mm的连续序列,最大化它的平均值。


    思路:

    很明显这道题的答案满足单调性。若可以找出一段区间的平均值超过kk,那么必然可以找到一段区间的平均值超过k1k-1
    那么可以考虑二分答案。
    设二分的答案为ansans

    (ija[i])÷(ji)ans(ji+1m)(sum^{j}_{i}a[i])div (j-i)geq ans(j-i+1geq m)

    ija[i]ans×(ji)sum^{j}_{i}a[i]geq ans imes (j-i)
    ija[i]ans×(ji)0sum^{j}_{i}a[i]-ans imes (j-i)geq 0
    ij(a[i]ans)0sum^{j}_{i}(a[i]-ans)geq 0
    于是可以用前缀和
    sum[i]=j=1i(a[i]ans)sum[i]=sum^{i}_{j=1}(a[i]-ans)
    然后我们就要最大化sum[i]sum[j](ij+1m)sum[i]-sum[j](i-j+1geq m)
    于是可以记录max(sum[k])(k1j1)max(sum[k])(kin 1sim j-1)。然后枚举ii,判断最大化后可否超过0。
    时间复杂度O(n log n)O(n log n)


    代码:

    #include <cstdio>
    #include <iostream>
    using namespace std;
    
    const int N=300010;
    int n,m;
    double l,r,mid,a[N],sum[N];
    
    bool check(double ans)
    {
    	sum[0]=0;
    	for (int i=1;i<=n;i++)
    		sum[i]=sum[i-1]+a[i]-mid;
    	double minn=0;
    	for (int i=m;i<=n;i++)
    	{
    		minn=min(minn,sum[i-m]);  //记录最小值
    		if (sum[i]>=minn) return 1;  //含有一个长度超过m的区间平均值超过0
    	}
    	return 0;
    }
    
    int main()
    {
    	freopen("average.in","r",stdin);
    	freopen("average.out","w",stdout);
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=n;i++)
    		scanf("%lf",&a[i]);
    	l=0;
    	r=1000000;
    	while (r-l>=0.0001)
    	{
    		mid=(l+r)/2.0;
    		if (check(mid)) l=mid;
    			else r=mid;
    	}
    	printf("%lf",l);
    	return 0;
    }
    
  • 相关阅读:
    努力的一分不会少
    C语言中的数组的访问方式
    代码的规划与规范化
    Manjaro中源码安装gcc7.1
    周围都是敌人,方法总比问题多
    elementary os 0.4.1下编译GCC-7.1源码并安装成功
    C语言中的基础知识变量探讨
    19年的桌面KDE的风雨和陪伴,没有什么能够割舍
    《手把手教你学C语言》学习笔记(10)--- 程序的循环控制
    copy 的实现原理与深浅拷贝
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998320.html
Copyright © 2011-2022 走看看