专栏文章

题解:CF2089B2 Canteen (Hard Version)

CF2089B2题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@minlanhh
此快照首次捕获于
2025/12/02 04:16
3 个月前
此快照最后确认于
2025/12/02 04:16
3 个月前
查看原文
题目很快就切了,全靠 tag 打的好。
做不出题怪大脑,胡出来题自称佬。
注意到答案上界为 nn 所以暴力模拟的操作次数为 n2n ^ 2 次 ,不可接受。注意到对于每次操作的 aia_ibib_i 其中必然有一个会清零,对于为零的值我们的操作实际上没有意义,所以我们本质上有意义的操作只有 nn 次。
考虑如何模拟过程中只模拟有意义操作,注意到可以用一个单调队列维护当前位置以及前面的 aa。对于一个位置 ii,要么 bib_i 清零,要么 单调队列清空,操作次数只有 nn 次,可以接受。
那有人就要问了,这只是 easy 版的做法,那 hard 版呢?莫慌莫慌,听我徐徐道来。我们可以二分答案,用上面的方法检验答案是否合法。这样时间复杂度为 O(nlogn)O(n \log n),可以通过。

code

CPP
#include<bits/stdc++.h>
using namespace std;
#define N 200005
int n, a[N], b[N];
long long k;
inline bool check(int x) {
	int aa[N], bb[N];
	long long ret = 0;
	deque<int> q;
	for(int i = n; i; --i) 
		aa[i] = a[i], bb[i] = b[i];
	for(int i = 1; i <= n; ++i) {
		q.push_back(i);
		while(!q.empty() && i - q.front() + 1 > x) 
			ret += aa[q.front()], q.pop_front();
		if(ret > k) return 0;
		while(!q.empty() && bb[i] >= aa[q.back()]) 
			bb[i] -= aa[q.back()], q.pop_back();
		if(!q.empty()) 
			aa[q.back()] -= bb[i], bb[i] = 0;
	}
	for(int i = 1; !q.empty() && i <= n; ++i) {
		while(!q.empty() && n - q.front() + i + 1 > x) 
			ret += aa[q.front()], q.pop_front();
		if(ret > k) return 0;
		while(!q.empty() && bb[i] >= aa[q.back()]) 
			bb[i] -= aa[q.back()], q.pop_back();
		if(!q.empty()) 
			aa[q.back()] -= bb[i], bb[i] = 0;
	}
	return 1;
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	int t;
	cin >> t;
	while(t--) {
		cin >> n >> k;
		for(int i = 1; i <= n; ++i) cin >> a[i];
		for(int i = 1; i <= n; ++i) cin >> b[i];
		int l = 0, r = n;
		while(l <= r) {
			int mid = l + r >> 1;
			if(check(mid)) r = mid - 1;
			else l = mid + 1;
		}
		printf("%d\n", r + 1);
	}
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...