• P1404 平均数


    题目描述

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

    输入格式

    第一行两个整数 nn 和 mm。

    接下来 nn 行,每行一个整数 a_iai​,表示序列第 ii 个数字。

    输出格式

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

    输入输出样例

    输入 #1复制

    10 6
    6
    4
    2
    10
    3
    8
    5
    9
    4
    1
    

    输出 #1复制

    6500
    

    说明/提示

    数据规模与约定

    • 对于 60\%60% 的数据,保证 m\le n\le 10^4m≤n≤104;
    • 对于 100\%100% 的数据,保证 1 \leq m\le n\le 10^51≤m≤n≤105,0\le a_i\le20000≤ai​≤2000。

    二分答案自然是平均数一类问题的常用思路。不过这题还有O(n)的算法(参见2004年集训队论文,周源)

    大体思路是先求部分和S(x),然后连续子序列平均值就转化为S-x平面上的斜率:ave(x,y)=(S(y)-s(x-1))/(y-x+1)。考虑x

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

    这个方法还可以求以每个点结尾的满足条件的最大平均数,这样子二分答案就不行啦,hoho~~

    二分答案 每次判断能不能满足存在长度大于m的子串的平均值>=mid就好 复杂度为O(n log 2000000)

    至于怎么判断可以把数列每一项减去mid 如果存在前缀和s[i]< s[j] && j-i>=m那么就满足条件

    1. #include
    2. #include
    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. double k(ll x,ll y){ // 计算s[x],s[y]的斜率
    10. return (s[y]-s[x]+0.0)/(y-x);
    11. }
    12. int main() {
    13. cin>>n>>m;
    14. for (ll i=1,x;i<=n;i++){
    15. cin>>x; s[i]=s[i-1]+x;
    16. }
    17. for (ll i=m;i<=n;i++){
    18. while (t-h>=2 && k(i-m,q[t-1])<k(i-m,q[t-2])) t--; // 删除上凸点
    19. q[t++]=i-m; // 入队
    20. while (t-h>=2 && k(i,q[h])<k(i,q[h+1])) h++; // 移动最大斜率点
    21. ans=max(ans,k(i,q[h]));
    22. }
    23. cout<<(ll)floor(ans*1000)<
    24. return 0;
    25. }

  • 相关阅读:
    jenkins配置maven+git自动构建jar包
    vector
    uniapp引入小程序原生插件
    Netty P1 NIO 基础,网络编程
    档案馆:如何做到水浸事件及时预警?
    Hive mapjoin使用
    Django REST framework API版本管理【通过GET参数传递】
    AVL树【图示详解+代码实现】
    华为机试真题 Python 实现【最大化控制资源成本】【2022.11 Q4 新题】
    【医学】基于Matlab实现 3-D 内表面轴细化算法构建骨架模型
  • 原文地址:https://blog.csdn.net/DUXS11/article/details/126181716