您的位置:首页 > 其它

欢迎使用CSDN-markdown编辑器

2016-07-26 09:12 113 查看

UVA1451

原文链接:

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4197

题意:给定一个长度为n的01串,计算出长度不小于L的连续子串的最大平均值。

要求:如果多解,长度尽量小,如果长度相同,起点编号应尽量小。

(1 <= n <= 100000, 1 <= L <= 1000)

例如:当n = 17, L = 7时,对于00101011011011010而言,最大平均值为6/8(子序列为[7, 14],长度为8)。

分析:

先求的前缀和Si = A1+A2+…+Ai, (S0 = 0),然后令点Pi = (i, Si), 则子序列i~j的值为(Sj - Si-1)/(j-(i-1)), 也就是直线Pi-1Pj的斜率K;

接下来只需判断点的凹凸情况即可。

首先,去掉所有上凸点,然后再判断剩下的所有点中切线斜率最大的点,即为所求。

// ConsoleApplication22.cpp : 定义控制台应用程序的入口点。
//

//#include "stdafx.h"//VS2015编译时需加上预编译头文件,其他编译器忽略
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 100000 + 5;

int n, L;
char s[maxn];
int sum[maxn], p[maxn];//sum[maxn]用来存放前缀和,
//p[maxn]用来存放暂时可行的下凸点

int Cmp_Ave(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);
}
//该表达式通俗一点,可以表示为:(y2-y1)*(x4-x3)-(y4-y3)*(x2-x1);
//也就是(y2-y1)/(x2-x1)-(y4-y3)/(x4-x3),表示的是两条直线之间斜率的大小关系
//等于0,表示斜率相等
//大于0,表示x1x2的斜率大于x3x4
//小于0,表示x1x2的斜率小于x3x4

int main()
{
int T;
cin >> T;
while (T--)
{
cin >> n >> L >> s + 1;
sum[0] = 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(p[j - 2], t - L, p[j - 1], t - L) >= 0)j--;//去除上凸点
p[j++] = t - L + 1;//加入新的
4000
候选点
//比较候选点与t点,更新斜率更大的点
while (j - i > 1 && Cmp_Ave(p[i], t, p[i + 1], t) <= 0)i++;
int c = Cmp_Ave(p[i], t, ansL, ansR);
//如果c大于0,表示找到更优答案,更新
//如果c等于0,则要判断序列是否更优
if (c > 0 || c == 0 && t - p[i] < ansR - ansL)
{
ansR = t;
ansL = p[i];
}
}
cout << ansL << " " << ansR << endl;
}
return 0;
}


这道题运用了数学中关于斜率的知识,最好需要结合图形,推敲一遍。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法UVA