uva 1451 数形结合

思路:枚举点t,寻找满足条件的点t‘;

计sum[i]为前i项合,平均值即为sum[t]-sum[t‘-1]/t-t‘+1

设(Pi=(i,Si),表示点在s中的位置,那么就可以画出坐标图,问题就转化为斜率最大;

于是画图分析。

几个点之间只有上凸下凸两种情况,取3个点为符合条件(t-t‘>=L)的t‘,分析后得结论上凸点在各种情况(t)下都要舍去;

于是就可以不断更新,更新策略为新插入点,删除掉原来是下凸点,插入后变成上凸点的点;

随着t增大,t‘只会增大(t增大,pt增大),所以增加到斜率变小时即可停止;

而且对于某个Pt,选好切点后,对于之后的Pt,之前的点Pt‘都不会用到了,于是不用从头枚举

代码

#include<cstdio>
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    //x1-x2的斜率大于x3-x4返回1
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;   //j是起始点中最右边的点,p[j]代表那个点在序列中的位置
    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
      //t-l是新加的点(上一步t-l+1,而for循环t++了),j-1(上一步j++了)是原来最右边的点,从最右边开始判断是否上凸

      p[j++] = t-L+1; // new candidate   //注意上一个循环已经去掉了右面的上凸点(j--)

      while (j-i > 1 && compare_average(p[i], t, p[i+1], t) <= 0) i++; // update tangent point切点

      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\n", ansL, ansR);
  }
  return 0;
}

原文地址:https://www.cnblogs.com/lqerio/p/9739593.html

时间: 2024-10-27 16:36:24

uva 1451 数形结合的相关文章

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,能得到的最大

【UVA 1451】Average

题 题意 求长度为n的01串中1占总长(大于L)的比例最大的一个子串起点和终点. 分析 前缀和s[i]保存前i个数有几个1,[j+1,i] 这段区间1的比例就是(s[i]-s[j])/(i-j),于是问题转换为找斜率最大的两个点. 如图,加入j时,就要去掉b1.b2,才能维护斜率的单调递增. 以队列里的点做起点,i 结尾的线段斜率最大的是 i和队列里点组成的下凹线的切线.切点前的点就不会再用到了,因为i后面的点和他们的斜率也将不如和这个切点的斜率. 数形结合,斜率优化,单调队列. 代码 #inc

UVA 1451 Average Seol 平均值

摘要:数形结合,斜率优化,单调队列. 题意:求一个长度为n的01串的子串,子串长度至少为L,平均值应该尽量大,多个满足条件取长度最短,还有多个的话,取起点最靠左. 求出前缀和S[i],令点Pi表示(i,S[i]),那么这个问题就转化成了求斜率最大的两点.画图分析可知,如果有上凸点,那么上凸点,一定不会是最优的,所以问题就变成了维护一个下凸的曲线.那么可以通过比较斜率来维护,而要求切点,在之前求出的一个切点之前的点一点不会得到更优的解. 假设在A点,即之前的切线之上,那么选切点以前的点,一定不是最

UVA 948 数的斐波那契进制表示

每个正整数都可以分解成斐波那契数列中的几个数相加-- 从大到小贪心法就可以了-- #include <iostream> #include <cstdio> #include <fstream> #include <algorithm> #include <cmath> #include <deque> #include <vector> #include <queue> #include <string

HDU3045 Picnic Cows (斜率DP优化)(数形结合)

转自PomeCat: "DP的斜率优化--对不必要的状态量进行抛弃,对不优的状态量进行搁置,使得在常数时间内找到最优解成为可能.斜率优化依靠的是数形结合的思想,通过将每个阶段和状态的答案反映在坐标系上寻找解答的单调性,来在一个单调的答案(下标)队列中O(1)得到最优解." https://wenku.baidu.com/view/b97cd22d0066f5335a8121a3.html "一些试题中繁杂的代数关系身后往往隐藏着丰富的几何背景,而借助背景图形的性质,可以使那些

UVa 11722 (概率 数形结合) Joining with Friend

高中也做个这种类似的题目,概率空间是[t1, t2] × [s1, s2]的矩形,设x.y分别代表两辆列车到达的时间,则两人相遇的条件就是|x - y| <= w 从图形上看就是矩形夹在两条平行线之间的部分. 因为情况众多,一个一个分类很麻烦,而且可能有漏掉情况,所以就用计算几何的办法求了个凸多边形,多边形 与 矩形面积之比就是概率. 代码有点挫,将就看,=_=|| 1 #include <cstdio> 2 #include <vector> 3 #include <

1451 - Average(数形结合)

该题表面让我们求一个字符串的问题,但是却可以转化成求斜率的问题, 紫书上已经说的很清楚了,我这里就不再赘述  . 代码如下 : #include<bits/stdc++.h> using namespace std; const int maxn = 100000 + 5; int n,T,L; double a[maxn],p[maxn]; char s[maxn]; int campare(int x1,int x2,int x3,int x4){ //直线p[x1]p[x2]的斜率减去p

UVa 1451 Average -斜率优化

A DNA sequence consists of four letters, A, C, G, and T. The GC-ratio of a DNA sequence is the number of Cs and Gs of the sequence divided by the length of the sequence. GC-ratio is important in gene finding because DNA sequences with relatively high

UVa1451 Average (数形结合,斜率优化)

链接:http://vjudge.net/problem/UVA-1451 分析:http://wenku.baidu.com/link?url=ntSYLfzAWxjlfpOKGTac0XYWhtwiMKvn2k1fI__R6JsJVXR_7b9GNijgkX2dPYJqIT5ri7_HS0EmFJZBwxe4bIX8IMWNOcjsMBziIMgC1s3 斜率优化.ave(i,j)=(Sj-Si-1)/(j-i+1)|j-i+1>=L|i尽量小,检查点从L开始枚举,用队列保存被检查点,维护一