算法学习之单调栈

文章描述了一个问题,涉及N个能量发射站按顺序排列,每个发射站根据其高度和能量值向两侧发射,接收能量的发射站根据邻近和高度规则计算接收能量。主要讨论了两种方法:直接模拟和使用单调栈优化求解,目标是找到接收最多能量的发射站。
摘要由CSDN通过智能技术生成

发射站

题目描述

某地有 N N N 个能量发射站排成一行,每个发射站 i i i 都有不相同的高度 H i H_i Hi,并能向两边(两端的发射站只能向一边)同时发射能量值为 V i V_i Vi 的能量,发出的能量只被两边最近的且比它高的发射站接收。显然,每个发射站发来的能量有可能被 0 0 0 1 1 1 2 2 2 个其他发射站所接受。

请计算出接收最多能量的发射站接收的能量是多少。

输入格式

1 1 1 行一个整数 N N N

2 2 2 N + 1 N+1 N+1 行,第 i + 1 i+1 i+1 行有两个整数 H i H_i Hi V i V_i Vi,表示第 i i i 个发射站的高度和发射的能量值。

输出格式

输出仅一行,表示接收最多能量的发射站接收到的能量值。答案不超过 32 位带符号整数的表示范围。

样例 #1

样例输入 #1

3
4 2 
3 5 
6 10

样例输出 #1

7

提示

对于 40 % 40\% 40% 的数据, 1 ≤ N ≤ 5000 , 1 ≤ H i ≤ 1 0 5 , 1 ≤ V i ≤ 1 0 4 1\le N\le 5000,1\le H_i\le 10^5,1\le V_i\le 10^4 1N5000,1Hi105,1Vi104

对于 70 % 70\% 70% 的数据, 1 ≤ N ≤ 1 0 5 , 1 ≤ H i ≤ 2 × 1 0 9 , 1 ≤ V i ≤ 1 0 4 1\le N\le 10^5,1\le H_i\le 2\times 10^9,1\le V_i\le 10^4 1N105,1Hi2×109,1Vi104

对于 100 % 100\% 100% 的数据, 1 ≤ N ≤ 1 0 6 , 1 ≤ H i ≤ 2 × 1 0 9 , 1 ≤ V i ≤ 1 0 4 1\le N\le 10^6,1\le H_i\le 2\times 10^9,1\le V_i\le 10^4 1N106,1Hi2×109,1Vi104

我们正常的思路就是直接模拟

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 1e+6 + 5;
int n;
ll h[N];
int v[N];
int ans[N];

int main() {
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> h[i] >> v[i];
	}
	h[0] = h[n+1] = 2000000000;
	for (int i = 1;i<=n; i++) {
		for (int j = i - 1; j > 0; j--) {
			if (h[j] > h[i]) {
				ans[j] += v[i];
				break;
			}
		}
		for (int j = i + 1; j <= n; j++) {
			if (h[j] > h[i]) {
				ans[j] += v[i];
				break;
			}
		}
	}
	int pp = 0;
	for (int i = 1; i <= n; i++) {
		pp = max(ans[i], pp);
	}
	cout << pp;
	return 0;
}

在这里插入图片描述
超时了两个点
在这里插入图片描述
我们需要维护一个单调栈

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 1e+6 + 5;
int n;
ll h[N];
int v[N];
int ans[N];
int q[N];

int main() {
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> h[i] >> v[i];
	}
	int top = 0; // 这是一个栈顶的
	for (int i = 1; i <= n; i++) {
		while (top && h[q[top]] < h[i]) // 出栈操作,这个必须保证里面有东西,且栈顶的是最小的, 如果进来的大于栈顶的,那么这个就要出栈
		{
			ans[i] += v[q[top--]];
		}
		// 进栈操作
		q[++top] = i;
		ans[q[top - 1]] += v[i];       // 给最近一个高的加上去
	}
	int pp = 0;
	for (int i = 1; i <= n; i++) {
		pp = max(pp, ans[i]);
	}
	cout << pp;
	return 0;
}

求m区间内的最小值

题目描述

一个含有 n n n 项的数列,求出每一项前的 m m m 个数到它这个区间内的最小值。若前面的数不足 m m m 项则从第 1 1 1 个数开始,若前面没有数则输出 0 0 0

输入格式

第一行两个整数,分别表示 n n n m m m

第二行, n n n 个正整数,为所给定的数列 a i a_i ai

输出格式

n n n 行,每行一个整数,第 i i i 个数为序列中 a i a_i ai 之前 m m m 个数的最小值。

样例 #1

样例输入 #1

6 2
7 8 1 4 3 2

样例输出 #1

0
7
7
1
1
3

提示

对于 100 % 100\% 100% 的数据,保证 1 ≤ m ≤ n ≤ 2 × 1 0 6 1\le m\le n\le2\times10^6 1mn2×106 1 ≤ a i ≤ 3 × 1 0 7 1\le a_i\le3\times10^7 1ai3×107

#include<iostream>
#include<cstdio>

const int N = 2000005;
int n, m;
int a[N];
int f[N];


int main() {
	int top = 0;
	int di = 1;
	scanf("%d%d", &n, &m);
	printf("0\n");
	f[++top] = 1;
	for (int i = 1; i <= n; i++) {
		scanf("%d", &a[i]);

		if (i >= 2) {
			// 出栈,先排除不在区间内的
			while (i - f[di] > m) {
				di++;
			}
			printf("%d\n", a[f[di]]);

			// 先进栈
			while (a[f[top]] >= a[i] && top >= di)
			{
				top--;
			}
			f[++top] = i;
		}
	}

	return 0;
}

用现成的工具
deque
operator[];//返回索引idx所指的数据,如果idx越界,不抛出异常,直接出错。

front();//返回第一个数据。

back();//返回最后一个数据

push_back(elem);//在容器尾部添加一个数据

push_front(elem);//在容器头部插入一个数据

pop_back();//删除容器最后一个数据

pop_front();//删除容器第一个数据

每日温度

在这里插入图片描述

class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& temperatures) {
        int len = temperatures.size();
        deque<int> p;
        vector<int> ans(len);
        for (int i = 0; i < len; i++) {
            int temp = temperatures[i];
            while (p.size() && temp > temperatures[p.back()]) {
                int po = p.back();
                cout << "尾巴的 " << po << endl;
                p.pop_back();
                ans[po] = i - po;
            }
            p.push_back(i);
        }
        return ans;
    }
};

leecode 1475

在这里插入图片描述

class Solution {
public:
    vector<int> finalPrices(vector<int>& prices) {
        int len = prices.size();
        vector<int> ans(len);
        deque<int> q;
        for (int i = 0; i < len; i++) {
            int now = prices[i];
            while (q.size()&&now<=prices[q.back()])
            {
                int pos = q.back();
                q.pop_back();
                ans[pos] = prices[pos] - now;
            }
            q.push_back(i);
        }
        // 别忘记这一步
        while(q.size()){
            int pos = q.back();
            ans[pos] = prices[pos];
            q.pop_back();
        }
        return ans;
    }
};

落谷2422

在这里插入图片描述
我们还要注意退出for循环后的边界处理,这时候单调栈里面还有东西

#include<bits/stdc++.h>
using namespace std;

#define int long long

const int N = 1e5 + 5;
int a[N];
int n;
int ans = 0;
int p[N];
int l[N], r[N];


signed main() {
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		p[i] = p[i - 1] + a[i];
		l[i] = r[i] = i;
	}
	deque<int> q;
	for (int i = 1; i <= n; i++) {
		int now = a[i];
		while (q.size()&& now<a[q.back()])
		{
			int  u = q.back();
			q.pop_back();
			r[u] = i;
		}
		q.push_back(i);
	}
	while (q.size()) {
		int u = q.back();
		q.pop_back();
		r[u] = n+1;
	}
	q.clear();
	for (int i = n; i >= 1; i--) {
		int now = a[i];
		while (q.size() && now < a[q.back()]) {
			int  u = q.back();
			q.pop_back();
			l[u] = i;
		}
		q.push_back(i);
	}
	while (q.size())
	{
		int u = q.back();
		q.pop_back();
		l[u] = 0;
	}
	for (int i = 1; i <= n; i++) {
		ans = max(ans, a[i] * (p[r[i]-1] - p[l[i]]));
	}
	//for (int i = 1; i <= n; i++) {
	//	cout << l[i] << " " << r[i] << endl;

	//}
	cout << ans;

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wniuniu_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值