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

    题目链接:平均数

    考虑两种算法:

    1、二分

    每次判断能不能满足存在长度大于m的子串的平均值>=mid【可以考虑使用前缀和优化】

    这个思路比较简单,代码:

     1 #define INF 0x7fffffff
     2 #include<cstdio>
     3 #include<iostream>
     4 #include<algorithm>
     5 using namespace std;
     6 const int MAXN=100010;
     7 long long a[MAXN],sum[MAXN];
     8 int n,m;
     9 inline int read()
    10 {
    11     int x=0,w=1;
    12     char c=getchar();
    13     while(c>'9'||c<'0'){if(c=='-') w=-1; c=getchar();}
    14     while(c<='9'&&c>='0'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    15     return w*x;
    16 }
    17 bool judge(int mid)
    18 {
    19     long long minn=INF;
    20     for(int i=1;i<=n;++i)
    21     {
    22        sum[i]=sum[i-1]+a[i]-mid;
    23        if(i>=m)
    24        {
    25          minn=min(minn,sum[i-m]);
    26          if(sum[i]>=minn)
    27          return true;
    28        }
    29     }
    30     return false;
    31 }
    32 int main()
    33 {
    34     n=read(),m=read();
    35     for(int i=1;i<=n;++i)
    36     a[i]=read(),a[i]*=10000;
    37     int l=0,r=20000000;
    38     while(l<r)
    39     {
    40       int mid=(l+r)>>1;
    41       if(judge(mid)) l=mid+1;
    42       else r=mid-1;
    43     }
    44     if(!judge(l)) --l;
    45     printf("%d
    ",l/10);
    46     return 0;
    47 }
    二分答案解法

    2、数学推导

    *发现很多题目跑的最快的算法都是别人的,比方说这题有人说是可以O(N)的


    先求部分和S(x),然后连续子序列平均值就转化为S-x平面上的斜率:ave(x,y)=(S(y)-s(x-1))/(y-x+1)。考虑x<y<z的三个点如果S(y)是上凸的,则这个点一定没贡献。所以有用的点构成一个下凸的折线

    用一个队列维护这个折线,加入新点时(如当前点为i,则新点为i-m),如果与队尾2个点形成上凸,则删除队尾点。如果队首2个点与当前点形成上凸,同理删除队首点。最后每次队首元素都是与点i斜率最大的点,再求最值就行了


    代码:

     1 #include <iostream>
     2 #include <cmath>
     3 #define N 100005
     4 typedef long long ll;
     5 using namespace std;
     6 ll n,m,s[N];
     7 double ans=0.0;
     8 ll q[N],t,h;   // 队列
     9 
    10 double k(ll x,ll y){  // 计算s[x],s[y]的斜率
    11     return (s[y]-s[x]+0.0)/(y-x);
    12 }
    13 int main() {
    14     cin>>n>>m;
    15     for (ll i=1,x;i<=n;i++){
    16         cin>>x; s[i]=s[i-1]+x;
    17     }
    18 
    19     for (ll i=m;i<=n;i++){
    20         while (t-h>=2 && k(i-m,q[t-1])<k(i-m,q[t-2])) t--;   // 删除上凸点
    21         q[t++]=i-m;  // 入队
    22         while (t-h>=2 && k(i,q[h])<k(i,q[h+1])) h++;  // 移动最大斜率点
    23         ans=max(ans,k(i,q[h]));
    24     }
    25 
    26     cout<<(ll)floor(ans*1000)<<endl;
    27     return 0;
    28 }
    O(N)解法

  • 相关阅读:
    C#添加修改删除文件文件夹大全
    实用且不花哨的js代码大全
    vs2005 2008快捷键
    C#:String.Format数字格式化输出
    获取农历日期
    Vim 常用快捷键
    一个简单的makefile示例及其注释
    nginx源码剖析(1)概要
    利用Vim 打造开发环境(一)>Linux 字符界面 vim的配置
    Ubuntu 9.10设置摘要
  • 原文地址:https://www.cnblogs.com/cptbtptpbcptbtptp/p/11299563.html
Copyright © 2011-2022 走看看