码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2015-02-08 11:35:15      阅读:315      评论:0      收藏:0      [点我收藏+]

标签:

题意:

给出一个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     //freopen("in.txt", "r", stdin);
15 
16     int T;
17     scanf("%d", &T);
18     while(T--)
19     {
20         scanf("%d%d", &n, &L); getchar();
21         for(int i = 1; i <= n; ++i) s[i] = getchar();
22         for(int i = 1; i <= n; ++i) sum[i] = sum[i-1] + s[i] - 0;
23 
24         int i = 0, j = 0, ansL = 0, ansR = L;
25         for(int t = L; t <= n; ++t)
26         {//枚举连续子串的右端点
27             while(j - i > 1 && cmp(p[j-2], t-L, p[j-1], t-L) >= 0) j--;//删掉下凸点
28             p[j++] = t-L+1;
29 
30             while(j - i > 1 && cmp(p[i], t, p[i+1], t) <= 0) i++;//找到切点使斜率最大
31             int c = cmp(p[i], t, ansL, ansR);
32             if(c > 0 || (c == 0 && t - p[i] < ansR - ansL)) { ansL = p[i]; ansR = t; }
33         }
34 
35         printf("%d %d\n", ansL, ansR);
36     }
37 
38     return 0;
39 }
代码君

 

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

标签:

原文地址:http://www.cnblogs.com/AOQNRMGYXLMV/p/4279797.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!