• P1404 平均数


    题目描述

    给一个长度为n的数列,我们需要找出该数列的一个子串,使得子串平均数最大化,并且子串长度>=m。

    输入输出格式

    输入格式:

     

    N+1行,

    第一行两个整数n和m

    接下来n行,每行一个整数a[i],表示序列第i个数字

     

    输出格式:

     

    一个整数,他是最大平均数的1000倍,如果末尾有小数,直接舍去,不要用四舍五入求整。

     

    输入输出样例

    输入样例#1: 
    10 6
    6
    4
    2
    10
    3
    8
    5
    9
    4
    1
    
    输出样例#1: 
    6500
    

    说明

    【数据范围】

    60% M<=N<=10000

    100% M<=N<=100000 0<=a[i]<=2000

    Solution:

      经典的二分答案问题。

      直接二分平均值,然后验证。

      验证时的思路是分数规划+前缀和,每个数都减去二分的值$mid$,并求出前缀和,问题转化为是否存在一个长度不小于$m$的子串使得其和大于等于$0$。显然子串右端点$i$范围为$[m,n]$,左端点$j$属于$[1,i-m+1]$,每次我们没有必要去枚举左端点,当右端点确定后,等价于判断$sum[i]-min(sum[j-1]),jin[1,i-m+1]$是否大于等于$0$,而每次$i$的右移一位只会使得$j$的最大值右移一位,那么我们直接记录一下可以选的左端点最小值就好了,然后就能$O(n)$扫一遍验证。

    代码:

    #include<bits/stdc++.h>
    #define il inline
    #define ll long long
    #define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
    #define Bor(i,a,b) for(int (i)=(b);(i)>=(a);(i)--)
    using namespace std;
    const int N=100005;
    int n,m;
    double a[N],b[N],s[N];
    
    il int gi(){
        int a=0;char x=getchar();bool f=0;
        while((x<'0'||x>'9')&&x!='-')x=getchar();
        if(x=='-')x=getchar(),f=1;
        while(x>='0'&&x<='9')a=(a<<3)+(a<<1)+x-48,x=getchar();
        return f?-a:a;
    }
    
    int main(){
        n=gi(),m=gi();
        For(i,1,n) a[i]=gi();
        double l=0,r=2005,mid;
        while(r-l>1e-5){
            mid=(l+r)/2;
            For(i,1,n) b[i]=a[i]-mid,s[i]=s[i-1]+b[i];
            double minn=1e10,ans=-1e10;
            For(i,m,n)  minn=min(minn,s[i-m]),ans=max(ans,s[i]-minn);
            (ans>=0)?(l=mid):(r=mid);
        }
        cout<<(int)(r*1000);
        return 0;
    }
  • 相关阅读:
    asp.net mvc3开发系统点滴之一
    C# winform 广告机 网络多媒体发布系统桌面版之一
    asp.net mvc3开发系统点滴之三
    js面向对象开发互联网机顶盒应用头端之五
    asp.net mvc3开发系统点滴之二
    【转载】指针空间的申请和释放(C)
    [转载]C 指针
    hoj2036
    hoj1142
    hoj1878
  • 原文地址:https://www.cnblogs.com/five20/p/9318473.html
Copyright © 2020-2023  润新知