题面:给出长度为n的数列,然后算出其区间和乘区间最小数所能得到的最大值,并且输出区间

样例输入:

6

3 1 6 4 5 2

样例输出:

60

3 5

原题链接:https://vjudge.net/problem/UVA-1619


分析:

这里有两种算法,一种是O(nlogn)的,用st表+递归,另一种是O(n)的,用单调栈。

容易知道对于数列中的每一个数作为相应区间最小值时,虽然这个相应区间不一定唯一的,但是这个最大区间和一定是唯一的。

举个栗子:

对于数列{0, 0, 0, 0, 0}来说,我们不管是选择哪一个元素作为区间最小值,其相应的答案区间都有多种可能,但最大区间和肯定都是0(你选取第一个0作为区间最小值, 那区间可以是[1, 1],[1, 2],[1, 3]等等,但是区间和最大值肯定都是0)。

我们看原题的话就会发现原题说明是关于这个区间的输出,我们输出其中合法的任何一个就行了。

但是!但是!其实这是在坑你!表面上是spj,实际上并不是spj!对于每一个给定的数据,其输出的区间也必须也是要跟他给的一毛一样才行orz,具体的潜规则我也不是很清楚,反正用单调栈才能AC,不过本着真理至上的原则,还是两个算法都讲一遍。

================

st表+递归解法

这种做法是枚举区间,然后通过st表O(1)找出区间的最小值,配合前辍和能直接计算出一个可能答案。

那怎么枚举区间呢?

先说下,st表保存的应该是区间最小值的下标 。

比较直观的一点就是当我们选取这个数列的最小值作为区间的最小值的时候,这个区间[1, n]肯定是合法的,设这个最小值的位置为k,那么我们可以知道[1, k-1], [k+1, n]这两个区间是另外两个该被枚举的区间,然后找出这两个区间最小值的位置,又能将区间再次分割。。。每次所划分的区间所对应的区间最小值所在的位置都是不一样的,通过这个递归过程,如此一来,我们就得到了一个O(n)枚举区间的方法,之所以这个算法是O(nlogn)只是因为建st表要O(nlogn)罢了,其他操作要么O(n)要么O(1)的,只可惜实际上这道题不是spj,这种方法跟单调栈的做法虽然都是对的,但是所得区间不一定一样,不然数据水点的话说不定也能过(x)。

 #include<iostream>
#include<cstdio>
#include<cstring>
using namespace std; const int N = 1e5 + ;
int Logn[N];
long long a[N];
long long sum[N]; //前辍和
int st[N][]; //记录区间[l, r]中最小元素下标的st表
long long ans; //最终答案
int L, R; //最终答案区间 void pre() {
Logn[] = ;
for (int i = ; i < N; i++)
Logn[i] = Logn[i / ] + ;
} void Build_st(int n) //建立st表
{
int logn = Logn[n];
for(int j=; j<=logn ;j++)
for (int i = ; i + ( << j) - <= n; i++) {
if (a[st[i][j - ]] < a[st[i + ( << (j - ))][j - ]])
st[i][j] = st[i][j - ];
else st[i][j] = st[i + ( << (j - ))][j - ];
}
} int Query(int l, int r)
{
int s = Logn[r - l + ]; if (a[st[l][s]] < a[st[r + - ( << s)][s]]) return st[l][s];
else return st[r + - ( << s)][s];
} void solve(int l, int r) //递归处理
{
if (l > r) return; int m = Query(l, r);
long long res = (sum[r] - sum[l-]) * a[m];
if (res > ans) {
ans = res;
L = l;
R = r;
} solve(l, m - );
solve(m + , r);
} int main()
{
//freopen("data.txt", "r", stdin);
//freopen("WA.txt", "w", stdout);
ios::sync_with_stdio(false);
pre();
int n;
while (cin >> n) {
ans = -; for (int i = ; i <= n; i++) {
cin >> a[i];
sum[i] = a[i] + sum[i - ];
st[i][] = i;
} Build_st(n);
solve(, n);
cout << ans << endl;
cout << L << " " << R << endl;
cout << endl;
} return ;
}

================

单调栈解法

单调栈的话做法就很单纯了,用数组l[i], r[i]分别保存元素a[i]作为区间最小值时所能延伸到的最左端跟最右端,用单调栈扫描两次这两个数组的值就能全部出来了,实际写代码的时候博主写惯了不小心写成了单调队列,不过操作都一样的。。。

 #include<iostream>
#include<algorithm>
#include<queue>
using namespace std; typedef long long ll;
const int Maxn = 1e5 + ;
ll a[Maxn];
ll l[Maxn];
ll r[Maxn];
ll sum[Maxn]; int main()
{
int n;
bool first = true;
while (cin >> n) {
if (first) first = false;
else cout << endl; for (int i = ; i <= n; i++) {
cin >> a[i];
sum[i] = sum[i - ] + a[i];
} deque <ll > rq, lq;
for (int i = ; i <= n; i++) {
while (!rq.empty() && a[rq.back()] > a[i]) {
r[rq.back()] = i - ;
rq.pop_back();
} rq.push_back(i);
}
while (!rq.empty()) {
r[rq.front()] = n;
rq.pop_front();
} for (int i = n; i >= ; i--) {
while (!lq.empty() && a[lq.back()] > a[i]) {
l[lq.back()] = i + ;
lq.pop_back();
} lq.push_back(i);
}
while (!lq.empty()) {
l[lq.front()] = ;
lq.pop_front();
} ll ans = ;
ll ans_l = , ans_r = ; for(int i=; i<=n ;i++)
if ((sum[r[i]] - sum[l[i] - ]) * a[i] > ans) {
ans = (sum[r[i]] - sum[l[i] - ]) * a[i];
ans_l = l[i];
ans_r = r[i];
} cout << ans << endl;
cout << ans_l << " " << ans_r << endl;
} return ;
}

Uva 1609 Feel Good的更多相关文章

  1. UVa 1609 - Foul Play

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

  2. UVa 1609 (博弈) Foul Play

    姑且把它归类为一道博弈吧,毕竟这也是在找必胜方案. 十分有意思的一道题目,设计一种方案让你支持的1队获胜. 题目给出了两个很重要的条件: 1队能打败至少一半的队伍 对于1队不能打败的黑队,一定存在一个 ...

  3. UVA 1609 Foul Play 不公平竞赛 (构(luan)造(gao)+递归)

    题意:有n支队伍(n是2的整数幂,2<=n<=4),打淘汰赛,胜者进入下一轮,其中1号队伍能打败至少一半的队伍,对于它不能打败的队伍l,一定存在一支它能够打败的队伍w,使得w能直接打败l, ...

  4. 紫书 例题8-17 UVa 1609 (构造法)(详细注释)

    这道题用构造法, 就是自己依据题目想出一种可以得到解的方法, 没有什么规律可言, 只能根据题目本身来思考. 这道题的构造法比较复杂, 不知道刘汝佳是怎么想出来的, 我想的话肯定想不到. 具体思路紫书上 ...

  5. uva 1354 Mobile Computing ——yhx

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAABGcAAANuCAYAAAC7f2QuAAAgAElEQVR4nOy9XUhjWbo3vu72RRgkF5

  6. UVA 10564 Paths through the Hourglass[DP 打印]

    UVA - 10564 Paths through the Hourglass 题意: 要求从第一层走到最下面一层,只能往左下或右下走 问有多少条路径之和刚好等于S? 如果有的话,输出字典序最小的路径 ...

  7. UVA 11404 Palindromic Subsequence[DP LCS 打印]

    UVA - 11404 Palindromic Subsequence 题意:一个字符串,删去0个或多个字符,输出字典序最小且最长的回文字符串 不要求路径区间DP都可以做 然而要字典序最小 倒过来求L ...

  8. UVA&&POJ离散概率与数学期望入门练习[4]

    POJ3869 Headshot 题意:给出左轮手枪的子弹序列,打了一枪没子弹,要使下一枪也没子弹概率最大应该rotate还是shoot 条件概率,|00|/(|00|+|01|)和|0|/n谁大的问 ...

  9. UVA计数方法练习[3]

    UVA - 11538 Chess Queen 题意:n*m放置两个互相攻击的后的方案数 分开讨论行 列 两条对角线 一个求和式 可以化简后计算 // // main.cpp // uva11538 ...

随机推荐

  1. RJM8L151F6P6温度枪方案对比

    疫情当下,温度计.呼吸机.监护仪.制氧机等医疗产品的生产供应至关重要,红外温度计属于非接触式测温,它是利用物体热辐射与物体温度之间的关系来工作的. 红外测温仪是一种将红外技术与微电子技术相结合的新型温 ...

  2. win10上使用linux命令

    (1)可以用windows自带的powershell,但是 ll,vim等命令不能使用 (2)Windows更新==>针对开发人员==>开启开发人员模式,然后在控制面板==>程序与功 ...

  3. VSTO开发指南(VB2013版) 第三章 Excel编程

    通过前两章的内容,有了一定的基础,但进入第三章,实例的步骤非常多,并且随着VS版本的升级,部分功能菜单界面发生了很大变化,所以,第三章的案例我将逐步编写! 实例3.1的目标就是给Excel写一个加载宏 ...

  4. Maven 仓库、坐标、常用命令

    maven中的仓库 需要jar包时,先到本地仓库中找,没有就从中央仓库去下载到本地仓库. 中央仓库很多都在国外,下载速度慢.国内的一些公司在自己的服务器上搭建了maven仓库(中央仓库的镜像),供内部 ...

  5. lua学习之深入函数第一篇

    深入函数第一篇 函数是第一类值,具有特定的词法域 第一类值 第一类值的意思是函数与 lua 中的其他类型如数字,字符串具有相同的权力 函数可以存储到全局变量或局部变量变量,还可以存储到 table 中 ...

  6. 算法训练 最大获利 注意数据规模(long long)

    资源限制 时间限制:1.0s   内存限制:256.0MB 问题描述 Chakra是一位年轻有为的企业家,最近他在进军餐饮行业.他在各地开拓市场,共买下了N个饭店.在初期的市场调研中,他将一天划分为M ...

  7. Jmeter连接数据库并使用数据表数据作为接口所需参数

    jmeter连接数据库,并且使用数据库的用户名密码进行登录操作,具体步骤如下: 1.参考博客<Jmeter连接SqlServer数据库并操作>进行相关内容的补充,修改JDBC Reques ...

  8. SQL中的事务ACID

    概述: 事务是由一系列语句构成的逻辑工作单元.事务和存储过程等批处理有一定程度上的相似之处, 通常都是为了完成一定业务逻辑而将一条或者多条语句“封装”起来,使它们与其他语句之间出现一个逻辑上的边界,并 ...

  9. php环境配置 wampserver 数据库无法连接

    开始接触php编程,最初级的选择了wampserver+phpstorm+notepad++.值得注意的有一下几点. 1.使用跳过不输入数据库密码登录数据库之后请及时修改数据库密码以及相关文件.否则在 ...

  10. Python中字符串的学习

    Python中字符串的学习 一.字符串的格式化输出 % 占位符 %s 字符串 %d integer %x 十六进制 integer %f float 指定长度 %5d 右对齐,不足左边补空格 %-5d ...