*【POJ - 2796】 Feel Good (前缀和优化+单调栈维护)

题干:

                                                            Feel Good

Time Limit: 3000MS Memory Limit: 65536K
Total Submissions: 12409 Accepted: 3484
Case Time Limit: 1000MS Special Judge

Description

Bill is developing a new mathematical theory for human emotions. His recent investigations are dedicated to studying how good or bad days influent people's memories about some period of life. 

A new idea Bill has recently developed assigns a non-negative integer value to each day of human life. 

Bill calls this value the emotional value of the day. The greater the emotional value is, the better the daywas. Bill suggests that the value of some period of human life is proportional to the sum of the emotional values of the days in the given period, multiplied by the smallest emotional value of the day in it. This schema reflects that good on average period can be greatly spoiled by one very bad day. 

Now Bill is planning to investigate his own life and find the period of his life that had the greatest value. Help him to do so.

Input

The first line of the input contains n - the number of days of Bill's life he is planning to investigate(1 <= n <= 100 000). The rest of the file contains n integer numbers a1, a2, ... an ranging from 0 to 10 6 - the emotional values of the days. Numbers are separated by spaces and/or line breaks.

Output

Print the greatest value of some period of Bill's life in the first line. And on the second line print two numbers l and r such that the period from l-th to r-th day of Bill's life(inclusive) has the greatest possible value. If there are multiple periods with the greatest possible value,then print any one of them.

Sample Input

6
3 1 6 4 5 2

Sample Output

60
3 5

解题报告:

     这个题干是真,的,恶,心。一会最大一会最小,搞这么复杂弄的题目看半天。。不过抽出核心部分就是一句话,求一个给定区间的    区间和与该区间最小值的  最大值。这题与HDU-1506那道Largest Rectangle(求最大矩形面积)差不多。

那道题的思路是:反正得是个矩形 还需要最大面积,那上底边一定和某一个高度相等吧?那我就把每个高度所能延伸到的最远距离(也就是矩形的长)求出来,最后"长"乘"高",里面肯定有我要的答案了啊。而求每一个高度对应的"长"的过程,也就是单调栈的过程。

本题也是一样,我就把每一个a[i] 都当做最小值,左边右边分别看看最远能延伸哪(这一步用单调栈),然后乘起来放在maxx里,维护maxx不就好了吗。

   另一个题解中的解释我觉得不错:

题意是给出一个序列,要求的是一个区间,这个区间的最小值乘以这个区间数字的和 是最大值。求这个最大值与这个区间。

即:给你n个数,求一个 max,其中max=某个区间和*该区间的最小值。

ac代码1:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<stack>
using namespace std;const int MAX = 1e6 + 5;
int a[MAX], L[MAX], R[MAX],  top;
long long sum[MAX];
int n;
int l,r;
long long maxx;
stack<int > sk;
int main()
{cin>>n;for(int i = 1; i<=n; i++) {scanf("%d",&a[i]);sum[i] = sum[i-1] + a[i];}//需要左侧第一个比a[i]小的元素,所以 从左向右维护一个严格单调递增栈 for(int i = 1; i<=n; i++) {while(!sk.empty() && a[sk.top() ] >= a[i]) sk.pop();if(sk.empty() ) L[i] = 0;else L[i] = sk.top();sk.push(i);}while(!sk.empty() ) sk.pop();//需要右侧第一个比a[i]小的元素,所以 从右向左维护一个严格单调递增栈 for(int i = n; i>=1; i--) {while(!sk.empty() && a[sk.top() ] >= a[i]) sk.pop();if(sk.empty() ) R[i] = n+1;else R[i] = sk.top();sk.push(i);}l=r=1;long long tmp;for(int i = 1; i<=n; i++) {tmp=sum[R[i] - 1 ] - sum[L[i] ];tmp*=a[i];if(tmp>maxx) {l=L[i]+1;r=R[i]-1;maxx=tmp;}	}
//	printf("%d   %d\n",L[4],R[4]);printf("%lld\n",maxx);printf("%d %d\n",l,r);return 0 ;} 

初始化的细节!!!!!

注意上面这个代码中,末尾的l=r=1是有讲头的,此处赋值成别的值就wa了。原因如下:(感谢wjh巨巨的分享)

     要么maxx赋初始值-1   要么写tmp>=maxx (这两种情况的l和r都不需要赋初始值)。

     如果你按ac代码中这样写,那就只能l=r=1才可以!! 因为这题卡了极限样例需要特判一下:这样输入:1\n0\n  或者1\n3\n你会发现输出都是你赋值的l


别的ac代码:(维护单调递减栈?也可以做?)(好像还是递增栈、、、)

实际上这个题目就是要对每一个节点进行扩展,这样扩展的话,复杂度是O(n^2)。减少时间复杂度要用单调栈,单调栈处理的问题就是对每一个节点进行扩展的问题,这个题目要维护的是一个单调递减栈,即从栈顶元素到栈底元素,值是单调递减的,即栈顶元素的值始终是栈的最大值。然后每一个值有属于自己的区间,这个区间目的是为了记录之后的元素向前延伸的用处。

向后延伸就靠从1到n扫描元素,(维护单调递减栈)这样当扫描的元素大于栈顶元素时,直接入栈。

当扫描的元素等于栈顶元素时,不记录,只将区间延伸到后面。

当扫描的元素小于栈顶元素时,这时要计算栈内当前的值。因为扫描的元素时小于栈顶元素的,要求的是一个区间的最小值,所以栈内那些大于该元素的值你会发现没有用处了,只需要将它们的那些区间留下来就对了,这就是向前扩展。

拿题目的sample举例子:

3 1 6 4 5 2

 

一开始每一个数都有自己的区间:

3(1,1)  1(2,2)  6(3,3)  4(4,4)  5(5,5)  2(6,6)  -1(7,7)后面加一个最小值,为了最后计算栈内元素使用。

先是3入栈。栈内元素 3(1,1)

1<3,首先计算一下栈内元素的值,记录下来。然后要把栈内大于1的全部弹出来,但是把它们的区间留下,栈内就变成了1(1,2)。实际上此时就会知道(1,2)这段区间之内的最小值是1。

6>1,直接入栈,栈内元素变为1(1,2),6(3,3)。

4<6,将6弹出,弹出之前计算值。然后栈内就变为1(1,2),4(3,4)。

5>4,直接入栈。栈内元素是1(1,2),4(3,4),5(5,5)。会发现因为5没有办法向前扩展了所以会知道5只能够在(5,5)的区间内最小,所以说站内元素是在自己区间的左端点与栈顶元素的右端点,这段区间之内满足着最小值的关系。1是在(1,5)这段区间内最小,4是在(3,5)这段区间内最小。这些值都会在碰到扫描的元素小于该元素时计算,记录下来,就是这样单调栈完成了对每一个元素进行左右扩展的目的。

2<5,2<4。要把5(5,5) 4(3,4)分别弹出,它们走之前要计算各自区间的值。

最后是-1,目的就是要将栈内所有元素弹出,计算每一个元素左右扩展的值。

#include <functional>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <queue>
#include <stack>
#include <map>
#include <bitset>
#include <set>
#include <vector>using namespace std;const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;
const double eps = 1e-15;
typedef long long LL;
typedef pair <int, int> PLL;static const int N = 100100;
stack <PLL> st;
int val[N];
LL sum[N];
int l[N];
int r[N];int main() {int n;while (~scanf("%d", &n)) {sum[0] = 0;for (int i = 1; i <= n; ++i) {scanf("%d", &val[i]);sum[i] = sum[i - 1] + val[i];l[i] = r[i] = i;}while (!st.empty()) {st.pop();}for (int i = n; i >= 1; --i) {if (st.empty()) {st.push(make_pair(val[i], i));}else {while (!st.empty()) {PLL u = st.top();if (val[i] >= u.first) {break;}st.pop();l[u.second] = i + 1;}st.push(make_pair(val[i], i));}}while (!st.empty()) {PLL u = st.top();st.pop();l[u.second] = 1;}for (int i = 1; i <= n; ++i) {if (st.empty()) {st.push(make_pair(val[i], i));}else {while (!st.empty()) {PLL u = st.top();if (val[i] >= u.first) {break;}st.pop();r[u.second] = i - 1;}st.push(make_pair(val[i], i));}}while (!st.empty()) {PLL u = st.top();st.pop();r[u.second] = n;}LL ans = -1;int L, R;for (int i = 1; i <= n; ++i) {int y = r[i];int x = l[i];if (ans < (sum[y] - sum[x - 1]) * val[i]) {ans = (sum[y] - sum[x - 1]) * val[i];L = x;R = y;}}printf("%lld\n", ans);printf("%d %d\n", L, R);}return 0;
}

总结:

    至今不明白为什么要维护一个严格单调递增栈。 

   答:因为你要的是一个严格小于你的元素,然后要取这两个下标中间的区域作为区间(因为中间就都是比你大的或相等的了)。所以,其实使用单调递增栈(以此举例)的目的不是为了找第一个严格比你小的值(虽然具体实现是这样的)而是为了找中间那部分都比你大的值的所在区间。严格单调递增栈(实现语句为带等号的 a[sk.top() ] >= a[i]   ->  then pop掉),找通过找严格小于他的第一个元素,目的是寻求大于等于他的那部分区间区域。这几个逻辑关系要搞清楚!!

(但有的题   用单调递减栈目的就是很单纯的找第一个比他高的元素,eg HDU 5033)稍后贴博客

与滑窗算法做区别?

滑动窗口的精髓是在一个数列里保存着一个递增数列,同时这个数列维持了它在原数列的位次递增,这个窗口里保存的第一个数即在这个区间里最小的数。这样不停得把新输入的数同这个滑动窗口里右边的数比较,如果比它大,删除窗口里的这个数,同时删除的数统治区域的最右边就是新输入的数,它的左统治区域即新输入的数的左统治区域,然后不停地向窗口的左边比。这样只需要一个数组记录它左边区域的边界就可以了,  右边同理..

附一个滑窗算法典型题目     【POJ - 2823】 Sliding Window

题解:https://blog.csdn.net/qq_41289920/article/details/81071905

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/440282.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringMVC配置视图的直接映射view-controller命名空间

通常情况下&#xff0c;如果直接通过url来访问具体的视图会报404错误&#xff0c;这个时候最容易想到的解决办法是通过转发或重定向机制&#xff0c;也就说走一遍目标控制器方法拦截一次。但是最好的方法是配置视图的直接映射关系。 <mvc: view-controller path"url访…

【nyoj-456】 邮票分你一半 (dp,0-1背包的中点问题)

题干&#xff1a; 邮票分你一半 时间限制&#xff1a;1000 ms | 内存限制&#xff1a;65535 KB 难度&#xff1a;3 描述 小珂最近收集了些邮票&#xff0c;他想把其中的一些给他的好朋友小明。每张邮票上都有分值&#xff0c;他们想把这些邮票分成两份&#xff0c;并且使…

Angular中父子组件传值@Input @Output @ViewChild最全面最简单的总结

父组件传递给子组件&#xff1a; 值传递方式&#xff1a;Input既可以传递数据也可以传递方法 传递数据&#xff08;不举例了&#xff09;传递方法 // 父组件定义方法 parentRun(){alert(这是父组件的 run 方法); } 调用子组件时传入当前方法&#xff08;是传递方法不是调用方…

《TCP/IP详解》学习笔记(七):广播和多播、IGMP协议

单播&#xff0c;多播&#xff0c;广播的介绍 1单播(unicast) 单播是说&#xff0c;对特定的主机进行数据传送。例如给某一个主机发送 IP 数据包。这时候&#xff0c;数据链路层给出的数据头里面是非常具体的目的地址&#xff0c;对于以太网来说&#xff0c;就是网卡的 MAC 地…

【 POJ - 3628 】Bookshelf 2(dfs 或 dp,0-1背包)

题干&#xff1a; Farmer John recently bought another bookshelf for the cow library, but the shelf is getting filled up quite quickly, and now the only available space is at the top. FJ has N cows (1 ≤ N ≤ 20) each with some height of Hi (1 ≤ Hi ≤ 1,0…

ES5总结1:数组Array新特性最全最精简的详解

2个位置方法&#xff1a;indexOf lastIndexOf 5个迭代方法&#xff1a;forEach every some filter map 2个高阶函数&#xff1a;reduce reduceRight &#xff08;可用于数组求和&#xff09; API: 1、indexOf(searchElement: T, fromIndex?: n…

Apollo自动驾驶入门课程第③讲 — 定位

目录 1. 定位的概述 2. 定位方法介绍 2.1 GNSS RTK 2.2 惯性导航 2.3 激光雷达定位 2.4 视觉定位 2.5 Apollo定位 本文转自微信公众号&#xff1a;Apollo开发者社区 原创&#xff1a; 阿波君 Apollo开发者社区 8月17日 上周我们发布了 Apollo入门课堂第②讲—高精地图&…

【HRBUST - 1621】迷宫问题II (bfs)

题干&#xff1a; 小z身处在一个迷宫中&#xff0c;小z每分钟可以走到上下左右四个方向的相邻格之一。迷宫中有一些墙和障碍物。 同时迷宫中也有一些怪兽&#xff0c;当小z碰到任意一个怪兽时&#xff0c;小z需要将怪兽消灭掉才可以离开此方格。但消灭 怪兽会花费一定的时间。…

Linux与Bash 编程——Linux文件处理命令-L1

目录&#xff1a; linux系统与shell环境准备 Linux系统简介操作系统简史Linux的发行版&#xff1a;Linux与Windows比较&#xff1a;Linux安装安装包下载Linux的访问方式远程登录方式远程登录软件&#xff1a;mobaxterm的使用&#xff1a;使用电脑命令行连接&#xff1a;sshd的…

4.Transfer Learning

Intro 这是深度学习第4课。 在本课程结束时&#xff0c;您将能够使用迁移学习为您的自定义目标构建高度准确的计算机视觉模型&#xff0c;即使您的数据相对较少。 Lesson [1] from IPython.display import YouTubeVideo YouTubeVideo(mPFq5KMxKVw, width800, height450) S…

Angular相关的有价值的问题集锦

001. Angular的三大核心概念是什么&#xff1f; 答&#xff1a;组件化、模块化和路由&#xff08;Component、NgModule、Router&#xff09;,其中最核心的概念是组件化Component。 002. 前端为什么需要Router&#xff1f; 答&#xff1a;如果没有Router&#xff0c;浏览器的…

如何在Word中排版出漂亮规整的编程语言代码样式?【☆】

[1] 能输出各种编程语言并保持代码格式和语法高亮显示的网站&#xff1a; PlanetB | Syntax Highlight Code in Word Documents http://www.planetb.ca/syntax-highlight-word Welcome! — Pygments http://pygments.org/ [2] How do you display code snippets in MS Wor…

网络编程懒人入门(一):快速理解网络通信协议(上篇)

转自即时通讯网&#xff1a;http://www.52im.net/ 原作者&#xff1a;阮一峰(ruanyifeng.com&#xff09;&#xff0c;本文由即时通讯网重新整理发布&#xff0c;感谢原作者的无私分享。 1、写在前面 论坛和群里常会有技术同行打算自已开发IM或者消息推送系统&#xff0c;很…

PCA算法中样本方差和协方差的无偏估计与n-1的由来

原文出处&#xff1a; http://blog.sina.com.cn/s/blog_c96053d60101n24f.html 在PCA算法中的方差协方差计算公式中除数为什么是n-1? 假设X为独立同分布的一组随机变量&#xff0c;总体为M&#xff0c;随机抽取N个随机变量构成一个样本&#xff0c;和是总体的均值和方差, 是常…

【Gym - 101915D】Largest Group(二分图最大团,状压dp)

题干&#xff1a; 大黑山上有小小民和小小涛两种物种&#xff0c;山东人小李想要研究这两种物种的关系 奇怪的是大黑山上有相同数量的小小民和小小涛。小李数了数一共有 P 个&#xff0c;小李分别给P个小小民和小小涛编号 1 - P 号&#xff0c;已知每对小小民之间都是好朋友&…

Apollo自动驾驶入门课程第④讲 — 感知(上)

目录 1. 感知的概述 2. 计算机视觉 3. 摄像头图像 4. LiDAR图像 5. 机器学习 6. 神经网络 7. 反向滤波法 本文转自微信公众号&#xff1a;Apollo开发者社区 原创&#xff1a; 阿波君 Apollo开发者社区 8月23日 上一篇文章中&#xff0c;我们发布了无人驾驶技术的 定位篇…

三种经典的洗牌算法

参考原文链接&#xff1a;https://blog.csdn.net/qq_25026989/article/details/89512769 问题描述&#xff1a;洗牌算法是将原来的数组进行打散&#xff0c;使原数组的某个数在打散后的数组中的每个位置上等概率的出现。 主要有3中经典的洗牌算法&#xff1a; 1.抽牌&#x…

【数据库实验课堂】实验一:数据库的管理

实验一&#xff1a;数据库的管理 1、假设SQL Server服务已启动&#xff0c;并以Administrator身份登录计算机&#xff08;文件名称自定&#xff09;&#xff1b;请分别使用Management界面方式和T-SQL语句实现以下操作&#xff1a; 1) 要求在本地磁盘D创建一个学生-课程数据库…

网络编程懒人入门(二):快速理解网络通信协议(下篇)

转自即时通讯网&#xff1a;http://www.52im.net/ 原作者&#xff1a;阮一峰(ruanyifeng.com&#xff09;&#xff0c;本文由即时通讯网重新整理发布&#xff0c;感谢原作者的无私分享。 1、前言 本文上篇《网络编程懒人入门(一)&#xff1a;快速理解网络通信协议&#xff0…

为什么说逻辑回归LR是线性分类器?

问题描述&#xff1a;为什么说逻辑回归LR是非常典型的线性分类器&#xff1f; 首先&#xff0c;我们要弄明白区分线性与非线性分类器的标准是什么&#xff1f;是决策边界&#xff08;Decision Boundary&#xff09; 以二分类&#xff08;LR可以用于多分类&#xff09;为例进行…