求求求求求助!注释很全!各位大佬看看为什么复杂度不对?
查看原帖
求求求求求助!注释很全!各位大佬看看为什么复杂度不对?
627886
duoaidaoc楼主2023/8/30 01:20
#include <limits.h>
#include <cstring>
#include <iostream>
#include <vector>
#include <algorithm>
#include <set>
#include <stack>
#include <map>
#include <cstdio>
#include <iomanip>
#include <deque>
#include <array>
#include <queue>
#define ll long long 
using namespace std;
const int N = 500020;
int n, d, k;
vector<array<int, 2>>block;

//比较第一个数字--"位置"的大小
int cmp(array<int, 2>a, array<int, 2>b) {
	return a[0] < b[0];
}
//离散化,求在block中第一个大于等于x的位置
int skup(int x) {
	array<int, 2> tmp = { x,0 };
	return lower_bound(block.begin(), block.end(), tmp, cmp) - block.begin();
}
//离散化,求在block中第一个小于等于x的位置
int skdn(int x) {
	array<int, 2> tmp = { x,0 };
	return upper_bound(block.begin(), block.end(), tmp, cmp) - block.begin() - 1;
}
int mx[N];
int dp[N];

//单调队列  元素权值 + 最后一次出现的位置
deque<array<int, 2>>qe;
//队列包含的区间
int qex, qey;

//移动单调队列的区间,具体为[x,y] -->> [x, yy] -->> [xx,yy] 其中x < xx , y < yy
void moveto(int xx, int yy) {
	//第一步移动y
	for (int i = qey + 1; i <= yy; i++) {
		if (qe.empty())//若为空直接push
			qe.push_back({ mx[i],i });
		else {//不为空
			while (!qe.empty() && qe.back()[0] < mx[i])//小于的pop
				qe.pop_back();
			if (qe.empty()) {//pop空了就直接push
				qe.push_back({ mx[i],i });
			}
			else {//不空看情况
				if (qe.front()[0] == mx[i]) {//相等,修改该权值 目前为止 最后一次出现的 位置(最大位置)
					qe.front()[1] = i;
				}
				else {//大于,小于的都pop掉了。
					qe.push_back({ mx[i],i });
				}
			}
		}
	}
	//第二步移动x
	for (int i = qex; i <= xx - 1; i++) {
		if (qe.empty()) {//空是异常现象,应该不存在,写着玩的。
			return;
		}

		//如果最大的元素的最大位置处于要pop的位置,那么pop
		if (mx[i] == qe.front()[0] && i == qe.front()[1]) {
			qe.pop_front();
		}
	}

	//修改他们俩
	qex = max(xx, 0);
	qey = max(yy, -1);
}

//在花钱为r的情况下判断是否能行
int solve(int r) {
	//初始化
	qe.clear();
	qex = 0, qey = -1;
	memset(mx, 0, sizeof(mx));
	moveto(0, 0);
	int maxt = INT_MIN;

	//dp[i] = front() + val[i]
	//本处是mx[i] = front(mx[l~r (r<i)]) + block[i][1];
	for (int i = 1; i <= n; i++) {
		//离散化查询从哪个区间可以转移过来log n
		int xx = skup(max(block[i][0] - (d + r), -1));
		int yy = skdn(min(block[i][0] - (d - r), block[i][0] - 1));
		if (yy < xx) continue;
		//区间滑动
		moveto(xx, yy);

		//状态转移;
		mx[i] = qe.front()[0] + block[i][1];
		maxt = max(mx[i], maxt);
		
		if (maxt >= k)
			return 1;
		//printf("%d %d %d %d\n", qex, qey, i, mx[i]);
	}
	return 0;
}
int main() {

	//存值
	cin >> n >> d >> k;
	block.push_back({ 0,0 });
	for (int i = 1; i <= n; i++) {
		int x, y;
		cin >> x >> y;
		block.push_back({ x,y });

	}

	//二分,log(500001),要不了多少吧
	int l = 0, r = 500001;
	while (l < r) {
		int mid = l + r >> 1;
		if (solve(mid)) {
			r = mid;
			//printf("%d true\n", mid);
		}
		else {
			l = mid + 1;
			//printf("%d false\n", mid);
		}
	}
	//如果r可以就输出否则输出不行
	if (solve(r)) {
		cout << r;
	}
	else {
		cout << -1;
	}
	
}
2023/8/30 01:20
加载中...