• UVa 1451 (数形结合 单调栈) Average


    题意:

    给出一个01串,选一个长度至少为L的连续子串,使得串中数字的平均值最大。

    分析:

    能把这道题想到用数形结合,用斜率表示平均值,我觉得这个想法太“天马行空”了

    首先预处理子串的前缀和sum,如果在坐标系中描出(i, sum[i])这些点的话。

    所求的平均值就是两点间的斜率了,具体来说,在连续子串[a, b]中,有sum[b]-sum[a-1]个1,长度为b-a+1,所以平均值为(sum[b]-sum[a-1])/(b-a+1)

    所以就把问题转化为:求两点横坐标之差至少为L-1,能得到的最大斜率。

    这道题和HDU 5033很相似,当时第一次见到用单调栈的解法,仅仅是凭着自己的理解写的题解,现在看来写得也十分蛋疼。

    还是紫书上讲得清楚透彻。

     1 #include <iostream>
     2 #include <cstdio>
     3 using namespace std;
     4 
     5 const int maxn = 100000 + 10;
     6 char s[maxn];
     7 int n, L, sum[maxn], p[maxn];
     8 
     9 int cmp(int a1, int b1, int a2, int b2)
    10 { return (sum[b1]-sum[a1-1]) * (b2-a2+1) - (sum[b2]-sum[a2-1]) * (b1-a1+1); }
    11 
    12 int main()
    13 {
    14     int T;
    15     scanf("%d", &T);
    16     while(T--)
    17     {
    18         scanf("%d%d", &n, &L); getchar();
    19         for(int i = 1; i <= n; ++i) s[i] = getchar();
    20         for(int i = 1; i <= n; ++i) sum[i] = sum[i-1] + s[i] - '0';
    21 
    22         int i = 0, j = 0, ansL = 0, ansR = L;
    23         for(int t = L; t <= n; ++t)
    24         {//枚举连续子串的右端点
    25             while(j - i > 1 && cmp(p[j-2], t-L, p[j-1], t-L) >= 0) j--;//删掉上凸点
    26             p[j++] = t-L+1;
    27 
    28             while(j - i > 1 && cmp(p[i], t, p[i+1], t) <= 0) i++;//找到切点使斜率最大
    29             int c = cmp(p[i], t, ansL, ansR);
    30             if(c > 0 || (c == 0 && t - p[i] < ansR - ansL)) { ansL = p[i]; ansR = t; }
    31         }
    32 
    33         printf("%d %d
    ", ansL, ansR);
    34     }
    35 
    36     return 0;
    37 }
    代码君
  • 相关阅读:
    下载文件
    文件上传后台
    触发器
    存储过程
    火狐浏览器不能获取 event,解决js报错问题
    Oracle 数据库--一个用户同步的sql
    基于二进制的权限控制
    自定义jsp标签
    http,socket和websocket
    正向代理和反向代理
  • 原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/4279797.html
Copyright © 2020-2023  润新知