Deltix Round, Summer 2021 (open for everyone, rated, Div. 1 + Div. 2) E(st表+思维)

16 篇文章 0 订阅
8 篇文章 0 订阅

题目大意:

有两个长度为 n n n的序列 a a a b b b q q q次询问,每次询问一个区间 [ l , r ] [l,r] [l,r],对于区间执行以下操作:

  • 选择 l ≤ p o s 1 ≤ p o s 2 ≤ . . . ≤ p o s k ≤ r ( k 为 偶 数 ) l \le pos_1 \le pos_2 \le ... \le pos_k \le r (k为偶数) lpos1pos2...poskrk,对于 a a a序列 p o s 1 , p o s 3 , p o s 5 , . . . pos_1,pos_3,pos_5,... pos1,pos3,pos5,...加1,对于 b b b序列 p o s 2 , p o s 4 , p o s 6 . . . pos_2,pos_4,pos_6... pos2,pos4,pos6...加1,对于每个区间最少多少次使得 ∀ i ∈ [ l , r ] , a i = b i \forall i \in [l,r], a_i = b_i i[l,r],ai=bi每次询问之间独立

解题思路:

  • 先把 b b b a a a差值求出来,令 d = b − a d=b-a d=ba
  • 一个区间 [ l , r ] [l,r] [l,r]合法的条件就 d d d l l l r r r的前缀和均大于等于0且l到r和为0(注意两者是有不同的)
  • 假设 d d d l l l r r r的前缀和, ∃ i ∈ [ l , r ] \exist i \in [l, r] i[l,r], 使得前缀和小于0,因为对于 d d d数组,每次都要先对大于0的减1,对小于0的加1,又因为操作位置是递增的,如果出现有前缀和小于0,则说明当前 i i i位置不管怎么利用前面大于0的d数组都无法变成0
  • 所以贪心最终答案就是 [ l , r ] [l,r] [l,r]前缀和的最大值
  • 那题目还有要求每次操作序列长度是偶数,其实加上这个条件就是相当于把这题变成类似最深的括号匹配深度,所以贪心是对的

AC代码:

#include <bits/stdc++.h>
#define ft first
#define sd second
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0) //不能跟puts混用
#define seteps(N) fixed << setprecision(N)
#define endl "\n"
const int maxn = 1e5 + 10;
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int, int> pii;
const ll mod = 1e9 + 7;
int n, q;
ll a[maxn], b[maxn], d[maxn], sum[maxn];
ll m1[20][maxn], m2[20][maxn];
int main() {
	cin >> n >> q;
	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++) d[i] = b[i] - a[i], sum[i] = sum[i - 1] + d[i], m1[0][i] = m2[0][i] = sum[i];
	for (int j = 1; j <= 18; j++) {
		for (int i = 1; i + (1 << j) - 1 <= n; i++) {
			m1[j][i] = min(m1[j - 1][i], m1[j - 1][i + (1 << (j - 1))]);
			m2[j][i] = max(m2[j - 1][i], m2[j - 1][i + (1 << (j - 1))]);
		}
	}
	int l, r;
	while (q--) {
		cin >> l >> r;
		if (sum[r] - sum[l - 1]) {
			puts("-1");
			continue;
		}
		int j = 31 - __builtin_clz(r - l + 1);
		ll mn = min(m1[j][l], m1[j][r - (1 << j) + 1]);
		ll mx = max(m2[j][l], m2[j][r - (1 << j) + 1]);
		if (mn - sum[l - 1] < 0) puts("-1");
		else cout << mx - sum[l - 1] << endl;
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值