2025.02.02

B3666

单调栈

用维护一个单调递减的栈,栈中存储下标,每遍历一个位置就加入栈并把小于它的元素都弹出,再把ans异或一遍

#include <bits/stdc++.h>
#define int unsigned long long 
using namespace std;
const int N = 1e6 + 5;
int n;
int a[N];
stack<int> s;
int ans;
signed main(){
	cin.tie(0);
	ios::sync_with_stdio(0);
	cin >> n;
	for(int i = 1; i <= n; i++) cin >> a[i];
	for(int i = 1; i <= n; i++){
		while(s.size() && a[i] > a[s.top()]){
			ans ^= s.top();
			s.pop();
		}
		s.push(i);
		ans ^= i;
		cout << ans << endl;
	}
	return 0;
}

P1725

DP, 单调队列优化

假设a_i​为第i格的冰冻指数,f_i​为跳到第i格所能获取的最大冰冻指数,那么状态转移方程为

f_i=max(f_j)+a_i(i-r<j<i-l)

再用单调队列优化

#include<bits/stdc++.h>
using namespace std;
const int N = 4e5 + 5;
int n, l, r;
int arr[N], dp[N];
deque<int> q;
signed main(){
	cin >> n >> l >> r;
	for(int i = 0; i <= n; i++) cin >> arr[i]; 
	memset(dp, -0x3f, sizeof(dp));
	dp[0] = 0;
	for(int i = 0; i <= n + r - l; i++){
    	while(q.size() && i - q.front() > r - l) q.pop_front();
    	while(q.size() && dp[q.back()] <= dp[i]) q.pop_back();
		q.push_back(i);
		dp[i + l] = dp[q.front()] + arr[i + l];
	}
	int ans = -0x3f3f3f3f;
	for(int i = n + 1; i <= n + r; i++) ans = max(ans, dp[i]);
	cout << ans;
	return 0;
}

P1439

单调队列+二分

把A中元素的位置记录下来,再依次输入B,每输入一个元素就二分查找A中对应的值,再找出最大值

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int a[N], b[N];
int n, x, rr;
int q[N], id[N];
int main(){
	cin >> n;
	memset(id, -1, sizeof id);
	for(int i = 1; i <= n; i++){
		cin >> x;
		id[x] = i;
	}
	q[0] = -1;
	for(int i = 1, x; i <= n; i++){
		cin >> x;
		int k = id[x];
		if(k == -1) continue;
		int r = lower_bound(q, q + rr, k) - q;
		q[r] = k;
		rr = max(rr, r + 1); 
	}
	cout << rr;
	return 0;
} 

P1631

把A和B从小到大排序,然后再相加得到N^2个和,可以发现:

A[1]+B[1]\leq A[1]+B[2]\leq \cdot \cdot \cdot \leq A[1]+B[N]

A[2]+B[1]\leq A[2]+B[2]\leq \cdot \cdot \cdot \leq A[2]+B[N]

\cdot \cdot \cdot

A[N]+B[1]\leq A[N]+B[2]\leq \cdot \cdot \cdot \leq A[N]+B[N]

首先,将这N个队列中的第一个元素放入一个堆中,然后,每次取出堆中的最小值。若这个最小值来自于第k个队列,那么,就将第k个队列的下一个元素放入堆中。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n, a[N], b[N];
priority_queue<int, vector<int>, greater<int> > q;
int main(){
	cin >> n;
	for(int i = 1; i <= n; i++) cin >> a[i];
	for(int i = 1; i <= n; i++) cin >> b[i];
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= n && (i - 1) * (j - 1) <= n; j++){
			q.push(a[i] + b[j]);
		}
	}
	int cnt = 0;
	while(q.size()){
		cout << q.top() << " ";
		q.pop();
		cnt++;
		if(cnt == n) break;
	}
	return 0;
} 

P2949

反悔贪心

把数据储存在pair里,先按照时间排序,再按照利润排序,每次有更好的且时间满了的时候就将堆中最小的拿出来去掉,换上利润高的。

#include<bits/stdc++.h>
#define pii pair<int, int>
#define d first
#define p second
#define int long long
using namespace std;
const int N = 1e5 + 5;
int n;
pii w[N];
priority_queue<int, vector<int>, greater<int> > q;
int ans;
signed main(){
	cin >> n;
	for(int i = 1; i <= n; i++) cin >> w[i].d >> w[i].p;
	sort(w + 1, w + 1 + n);
	for(int i = 1; i <= n; i++){
		if(w[i].d == q.size()){
			if(w[i].p > q.top()){
				ans -= q.top();
				q.pop();
				q.push(w[i].p);
				ans += w[i].p;
			}
		}
		else{
			q.push(w[i].p);
			ans += w[i].p;
		}
	}
	cout << ans;
	return 0;
} 

P1717

贪心

枚举每个鱼塘,算出时间,选最好的那个

#include<bits/stdc++.h>
#define pii pair<int, int>
#define x first
#define y second
using namespace std;
const int N = 30;
int n, T, f[N], d[N], ne[N], ans;
signed main(){
	cin >> n >> T;
	for(int i = 1; i <= n; i++) cin >> f[i];
	for(int i = 1; i <= n; i++) cin >> d[i];
	for(int i = 1; i < n; i++) cin >> ne[i];
	for(int i = 1; i <= n; i++){
		priority_queue<pii> q;
		int tt = T * 12;
		for(int j = 1; j <= i; j++) q.push({f[j], d[j]});
		for(int j = 1; j < i; j++) tt -= ne[j];
		int res = 0;
		while(tt > 0){
	        pii t = q.top();
	        res += t.x;
	        tt--;
	        if(t.x <= 0) break;
	        q.pop();
	        q.push({t.x - t.y, t.y});
		}
		ans = max(ans, res);
	}
	cout << ans;
	return 0;
} 

P4588

线段树

将数据按时间排序,建线段树,维护区间乘。这样的话根节点就是到现在为止的所有数的乘积。

第一个操作就是将当前时间的值设为m。

第二个操作就是将pos时的值置为1。

#include<bits/stdc++.h>
#define int long long
#define ls u << 1
#define rs u << 1 | 1 
using namespace std;
const int N = 1e5 + 5;
int op, T, n, m, M;
struct node{
	int l, r, mul;
}tr[N << 2];
void pushup(int u){
	tr[u].mul = (tr[ls].mul * tr[rs].mul) % M;
}
void build(int u, int l, int r){
	tr[u] = {l, r, 1};
	if(l == r) return;
	int mid = l + r >> 1;
	build(ls, l, mid);
	build(rs, mid + 1, r);
	pushup(u);
}
void update(int u, int pos,int c){
	if(tr[u].l == tr[u].r && tr[u].l == pos){
		tr[u].mul = c;
		return;
	}
	int mid = tr[u].l + tr[u].r >> 1;
	if(pos <= mid) update(ls, pos, c);
	if(pos > mid) update(rs, pos, c);
	pushup(u);
}
signed main(){
	cin >> T;
	while(T--){
		cin >> n >> M;
		memset(tr, 0, sizeof(tr));
		build(1, 1, n);
		for(int i = 1, x; i <= n; i++){
			cin >> op >> x;
			if(op == 1){
				update(1, i, x);
			}else{
				update(1, x, 1);
			}
			cout << tr[1].mul << endl;
		}
	}
	return 0;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值