最后一个点过不了,求助QAQ
查看原帖
最后一个点过不了,求助QAQ
324632
Skeleton_Huo楼主2022/7/18 13:36
/*
1.二分d 
2.fd[i] = max(1 <= k < i, x[i]-d-g <= x[k] <= x[i]-d+g) { fd[k] + s[i] }
  单调队列优化 
3.若 max x[i] < k, 令 d 的左边界收缩 
  若 max x[i] >= k, 令 d 的右边界收缩 
  原因: 若 d < d', 则d可能的情况包含在d'中, 所以max fd[i] <= max fd'[i] 
*/

#include <iostream>
#include <cstdio>
#include <cstring>

#define ll long long

using namespace std;

const int N = 5e5 + 10, INF = 0x3f3f3f3f;

int n, d, k;
int x[N], s[N];
ll f[N];
int head, tail, q[N];

ll dp(int g) {
	int l, r;
	if (g < d) l = d - g, r = d + g;
	else l = 1, r = d + g;
//	printf("l:%d r:%d\n", l, r);
	
	memset(f, -INF, sizeof f);
	f[0] = s[0];
	
	head = tail = 0;
	int j = 0; ll res = 0;
	for (int i = 1; i <= n; i++) {
		while (j < i && x[j] <= x[i] - l) {		// 不要取 max(0, x[i] - l) 
			// 一定要先push, 否则会导致该pop的没pop掉 
			while (head < tail && f[j] > f[q[tail - 1]]) tail--;
			q[tail++] = j;
			j++;
		}
		
		// pop
		while (head < tail && x[q[head]] < x[i] - r) head++;	// 这里也不需要取max(0, x[i] - r) 
		
//		printf("queue: ");
//		for (int  k = head; k < tail; k++) {
//			printf("%d:%d ", q[k], f[q[k]]);
//		}
//		puts("");
		
		// 计算 
		if (head == tail) f[i] = -INF;
		else f[i] = f[q[head]] + s[i];
//		printf("f[%d]=%d\n", i, f[i]);
		res = max(res, f[i]);
	}
	
	return res;
}

signed main() {
//	freopen("P3957_10.in", "r", stdin);
//	freopen("P3957_10_.out", "w", stdout);
	
	scanf("%d%d%d", &n, &d, &k);
	
	x[0] = s[0] = 0;
	for (int i = 1; i <= n; i++) {
		scanf("%d%d", &x[i], &s[i]);
	}
	
	int l = 0, r = 2001, mid;	// 2001用于检测无解 
	
	while (l < r) {		// 找到第一个[0,2000]中,第一个使dp()>=k的值. 
		mid = (l + r) >> 1;
		if (dp(mid) >= k) {
			r = mid;
		} else {
			l = mid + 1;
		}
	}
	
//	printf("%d", dp(2));
	
	if (r == 2001) printf("-1");
	else printf("%d", r);
	
//	fclose(stdin);
//	fclose(stdout);
	
	return 0;
}
2022/7/18 13:36
加载中...