zoukankan      html  css  js  c++  java
  • P1404 平均数

    描述:
    (给一个长度为 n 的数列,我们需要找出该数列的一个子串,使得子串平均数最大化,并且子串长度 ≥m。)

    题目传送门:平均数

    题目算法:二分+DP+思维

    分割线

    又是束手无策的一道题目,理解起来也很反人类.......以下见解摘自这位dalao

    Ⅰ.如何进行二分

    二分最大平均值,然后进行验证。如何验证?将序列中的元素减去平均值

    如果有一段长度不小于L的区间和大于等于0,说明该平均值可行,调整边界,继续二分。

    Ⅱ.如何求有限制性最大子段和

    方法1

    求一个子段,它的和最大,没有“长度不小于L”这个限制。这个可以用动态规划解决。 (d[i]=max(d[i-1]+A[i],0.0));

    (d[i])为以i结尾的最大子段和

    如何将“限制性”转化为一般情况:

    (s[i])为以i结尾且长度不小于L的最大子段和,(A[i])为原数组,(sum[i])为前缀和。

    因为长度要不小于L,所以从(A[i-L])一直到(A[i])是必选的,总和为(sum[i]-sum[i-L]),前面(i-L)个数可选可不选

    要想和最大,就要加上以(a[i-L])结尾的最大子段和,所以(s[i]=sum[i]-sum[i-L]+d[i-L]) (前面(i-L)个数的最大子段和)

    最后在(s[i])中取一个最大值就是(ans)。也可以不用s数组,直接在过程中取最大值

    方法2

    最大子段和可以转化为前缀和相减的形式。

    设sum[i]为序列A的前i项的和 ,设s[i]是序列A以A[i]结尾且长度不小于L的最大连续子段和

    那么显然有: (s[i] = sum[i] - min){(sum[j])}((0<=j<=i-L))

    这里的代码用的是第一种方法。

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=100009;
    const double eps=1e-7;
    int n,m;
    double a[maxn],b[maxn],dp[maxn],sumn[maxn];
    bool check(double mid)
    {
    	for(int i=1;i<=n;i++)
    	{
    		b[i]=a[i]-mid;
    		sumn[i]=sumn[i-1]+b[i];
    		dp[i]=max(dp[i-1]+b[i],0.0);
    	}
    	for(int i=m;i<=n;i++)
    		if(dp[i-m]+sumn[i]-sumn[i-m]>=0)	return true;
    	return false;
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	double l=0,r=0,mid;
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%lf",&a[i]);
    		r=max(r,a[i]);
    	}
    	while(r-l>eps)
    	{
    		mid=(l+r)/2.0;
    		if(check(mid))	l=mid;
    		else	r=mid;
    	}
    	printf("%d",int(r*1000));
    }
    
  • 相关阅读:
    2.4 使用vue-cli创建项目/项目打包/发布
    2.3 vue-cli脚手架工具/nodejs
    2.2 vue的devtools、eslint检测问题
    2. es6扩展运算符
    文件json
    函数
    函数不固定参数
    监控日志,加入黑名单
    非空即真
    随机生成手机号,存入文件
  • 原文地址:https://www.cnblogs.com/iss-ue/p/12579227.html
Copyright © 2011-2022 走看看