UVA 1451 Average Seol 平均值

摘要:数形结合,斜率优化,单调队列。

题意:求一个长度为n的01串的子串,子串长度至少为L,平均值应该尽量大,多个满足条件取长度最短,还有多个的话,取起点最靠左。

求出前缀和S[i],令点Pi表示(i,S[i]),那么这个问题就转化成了求斜率最大的两点。画图分析可知,如果有上凸点,那么上凸点,一定不会是最优的,所以问题就变成了维护一个下凸的曲线。那么可以通过比较斜率来维护,而要求切点,在之前求出的一个切点之前的点一点不会得到更优的解。

假设在A点,即之前的切线之上,那么选切点以前的点,一定不是最优的,假设在B点,原来的切线之下,那么,怎么也得不到一个斜率比之前切线更大的线。

更具体得可以看这篇论文:浅谈数形结合思想在信息学竞赛中的应用

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+233;
char s[maxn];
int sum[maxn],q[maxn];

#define seg(x1,x2) (sum[x2]-sum[x1-1])
inline int cmp_ave(int x1,int x2,int x3,int x4){
    return seg(x1,x2)*(x4-x3+1) - seg(x3,x4)*(x2-x1+1);
}

int main()
{
    //freopen("in.txt","r",stdin);
    int T; scanf("%d",&T);
    while(T--){
        int n,L;
        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;
        int i = 0,j = 0;
        for(int t = L; t <= n; t++){
            while(j-i>1 && cmp_ave(q[j-2],t-L,q[j-1],t-L) >= 0)j--;
            q[j++] = t-L+1;
            while(j-i>1 && cmp_ave(q[i],t,q[i+1],t) <= 0) i++;
            int c = cmp_ave(q[i],t,ansL,ansR);
            if(c > 0|| c == 0 && t-q[i] < ansR - ansL){
                ansL = q[i]; ansR = t;
            }
        }
        printf("%d %d\n",ansL,ansR);
    }
    return 0;
}
时间: 2024-11-11 06:29:18

UVA 1451 Average Seol 平均值的相关文章

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

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

1451 - Average 快速求平均值

如何快速求取一段区间的平均值 用前缀的思想来看 非常简单 但是 本题题意要求的是 大于等于一段长度的区间的平均值的最大值 而且给出的数据范围很大 O(n*L)的直白比较算法 用于解决此问题不合适 这种情况下 可以考虑用斜率来表示平均值 然后通过对斜率的讨论和比较斜率来找出最大平均值 我感觉是维护一个从当前点往前的最大斜率--去除上凸点(它和当前点的连线肯定不能是最大斜率) code(别人的orz...) #include <stack> #include <cstdio> #inc

1451 - Average 高速求平均值

怎样高速求取一段区间的平均值 用前缀的思想来看 很easy 可是 本题题意要求的是 大于等于一段长度的区间的平均值的最大值 并且给出的数据范围非常大 O(n*L)的直白比較算法 用于解决此问题不合适 这样的情况下 能够考虑用斜率来表示平均值 然后通过对斜率的讨论和比較斜率来找出最大平均值 我感觉是维护一个从当前点往前的最大斜率--去除上凸点(它和当前点的连线肯定不能是最大斜率) code(别人的orz...) #include <stack> #include <cstdio> #

【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 数形结合

思路:枚举点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增大),所以增加到斜率变

uva 1451(树形结合)

求y/x的最大,其实就是求斜率最大 #include <iostream> #include <cstring> #include <cstdio> #include <algorithm> using namespace std; const int maxn=100000+10; char ss[maxn]; int sum[maxn],q[maxn]; int n,m,t; int solve(int x1,int x2,int x3,int x4)

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

【ECharts】SSH+JQueryAjax+Json+JSP将数据库中数据填充到ECharts中

1导入包,搭建SSH框架. 导入JQuery的JS包,<script src="JS/jquery-1.7.1.js"></script> 导入ECharts的包.<script src="http://s1.bdstatic.com/r/www/cache/ecom/esl/1-6-10/esl.js"></script> 前提你的SSH已经搭好了,数据已经传递到了Struts层. 2在Action层,将数据封装成J