ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

P8539 「Wdoi-2」来自地上的支援 题解

2022-09-13 19:32:35  阅读:153  来源: 互联网

标签:P8539 return int 题解 最大值 个数 mid 选中 Wdoi


思路

根据题意,如果每次询问选中的为第 \(x\) 个数,那么前 \(x-1\) 次操作一定不会选中第 \(x\) 个数。(感觉在说废话。

同样,因为第 \(x\) 个数必须被选中 \(k\) 次,根据题意,不难发现这 \(k\) 次选中一定是从第 \(x\) 次操作到 \(x+k-1\) 次操作被选中。因为如果某个数在某次操作时没有被选中,那么他在后面的操作中肯定不会再次被选中。

根据上面的思路,我们要修改的最小值 \(s\) 必须大于等于前 \(x-1\) 个数进行 \(x-1\) 次操作后的最大值,我们可以用一个前缀数组来维护,数组的每个值 \(pre_i\) 表示前 \(i-1\) 个数进行 \(i-1\) 次操作后的最大值,然后再向后枚举 \(k-1\) 个数,每次都和进行过若干次操作后的最大值比较,如果枚举到的值比最大值大,就讲当前的最大值修改为枚举到的值加一(操作的第二个性质),这样就可以得到答案。

这时你就可以得到 \(65\) 分的好成绩。

优化

很显然,对于上面向后枚举 \(k-1\) 个数的操作是可以进行优化的。

因为要区间查询最大值,所以不妨考虑一下线段树,但现在问题出现在如果维护最大值上。

我们可以考虑在维护线段树时同时记录下最大值和最大值所在的坐标。然后在两个数相比较的时候,比较 \(a_i+(j-i)\times v\) 和 \(a_j\) 的大小(\(i\le j\))。根据这样比较的结果选出最大值来,这样我们只需要把 \(s\) 修改为 \(\max\left\{ pre_x,a_p-(p-x)\times v+1 \right\}\) (\(p\) 表示最大值所在的下标)即可。

代码

#include <bits/stdc++.h>
#define int long long
#define ls x<<1
#define rs x<<1|1
#define N 2000010
using namespace std;

struct node {
	int val, st;
};
int n, m, v, a[N], pre[N], ans1, ans2;
node maxn[N << 2];

node max(node x, node y) {
	if (x.st > y.st) {
		if ((x.st - y.st)*v + y.val < x.val) {
			return x;
		} else {
			return y;
		}
	} else {
		if ((y.st - x.st)*v + x.val < y.val) {
			return y;
		} else {
			return x;
		}
	}

}

void bulid(int x, int l, int r) {
	if (l == r) {
		maxn[x] = node{a[l], l};
		return;
	}

	int mid = l + r >> 1;
	bulid(ls, l, mid);
	bulid(rs, mid + 1, r);
	maxn[x] = max(maxn[ls], maxn[rs]);
}

node query(int x, int l, int r, int L, int R) {
	if (l >= L && r <= R) {
		return maxn[x];
	}


	int mid = l + r >> 1;

	if (R <= mid) {
		return query(ls, l, mid, L, R);
	} else if (L > mid) {
		return query(rs, mid + 1, r, L, R);
	} else {
		return max(query(ls, l, mid, L, R), query(rs, mid + 1, r, L, R));
	}
}

signed main() {
	scanf("%lld%lld%lld", &n, &m, &v);
	int maxn = 0;

	for (int i = 1; i <= n; i++) {

		scanf("%lld", &a[i]);
		pre[i] = maxn;
		maxn = max(maxn, a[i]) + v;
	}

	bulid(1, 1, n);

	while (m--) {
		int x, k;
		scanf("%lld%lld", &x, &k);

		if (k > n - x + 1) {
			continue;
		}

		int s = pre[x];
		if(k==1){
			ans1 ^= s;
			ans2 += s;
			continue;
		}
		node tmp = query(1, 1, n, x + 1, x + k - 1);

		if (s <= tmp.val - (tmp.st - x)*v) {
			s = tmp.val - (tmp.st - x) * v + 1;
		}

		ans1 ^= s;
		ans2 += s;
	}

	printf("%lld %lld", ans1, ans2);
	return 0;
}

标签:P8539,return,int,题解,最大值,个数,mid,选中,Wdoi
来源: https://www.cnblogs.com/Dregen-Yor/p/16690428.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有