• UVa 1451 平均值 数形结合


    题意:给定一个长度为n 的01串,然后选一个长度至少为L的子串,使得子串的平均值最大。

    分析:
    不会做,学习一下。可以参考这篇论文:http://wenku.baidu.com/link?url=Mz_53YzQ6hJLkXpIS9v3Uo3k9CGF4hgkcSzY5EhV5XbsF3HkW2Ae4EGCXaIdm4380TneqShe63xuTRJvHebPcPAKdUKuIRWkM04LcjSv2nK
    树形结合,将字符串的每个位置对应成xOy坐标上的点,那么平均指即为两点之间的斜率。
    然后维护一个相邻两点斜率递增的一个集合q(即凸点集),然后后面枚举的点只需要在这个集合中找切点即为该点满足题意的最优斜率。注意比如从1~5,有3个‘1’,除数不是5-1=4,要注意它占了1,2,3,4,5,5个位置,所以除数是5,所以枚举两点的时候要注意。

    #include<cstdio>
    #include<iostream>
    using namespace std;
    
    const int maxn = 100000 + 5;
    
    int n, L;
    char s[maxn];
    int sum[maxn], p[maxn]; // average of i~j is (sum[j]-sum[i-1])/(j-i+1)
    
    // compare average of x1~x2 and x3~x4
    int compare_average(int x1, int x2, int x3, int x4) {
      return (sum[x2]-sum[x1-1]) * (x4-x3+1) - (sum[x4]-sum[x3-1]) * (x2-x1+1);
    }
    
    int main() {
      int T;
    
      scanf("%d", &T);
    
      while(T--) {
        scanf("%d%d%s", &n, &L, s+1);
    
        sum[0] = 0;
        for(int i = 1; i <= n; i++) sum[i] = sum[i-1] + s[i] - '0';
    
        int ansL = 1, ansR = L;
    
        // p[i..j) is the sequence of candidate start points
        int i = 0, j = 0;
        for (int t = L; t <= n; t++) { // end point
    
          while (j-i > 1 && compare_average(p[j-2], t-L, p[j-1], t-L) >= 0) j--; // remove concave points 删去上凸点,
          p[j++] = t-L+1; // new candidate
    
          while (j-i > 1 && compare_average(p[i], t, p[i+1], t) <= 0) i++; // update tangent point
    
          // compare and update solution
          int c = compare_average(p[i], t, ansL, ansR);
          if (c > 0 || c == 0 && t - p[i] < ansR - ansL) {
            ansL = p[i]; ansR = t;
          }
        }
        printf("%d %d
    ", ansL, ansR);
      }
      return 0;
    }
  • 相关阅读:
    放大镜
    简单拖拽加边界处理加轨迹返回
    事件委托
    数组的方法
    数据处理
    数组去重
    字符串的操作方法
    函数的递归调用
    选择排序、冒泡排序
    Linux—shell中$(( ))、$( )、``与${ }的区别
  • 原文地址:https://www.cnblogs.com/01world/p/5651206.html
Copyright © 2020-2023  润新知