Codeforces Round #741 (Div. 2) D. Two Hundred Twenty One (easy & hard version)(思维 + 前缀和)

链接 D2. Two Hundred Twenty One (hard version)

题意

给出以个只包含 + + + − - 的字符串,奇数位为 1 1 1,偶数位为 − 1 -1 1 + + + 1 1 1 − - − 1 -1 1,每一位的值 = ( 奇 o r 偶 ) =(奇or偶) =or数位 ∗ ( + o r − ) * (+or-) +or;给出 q q q 个询问,问需要删除几个数才能保证区间内的所有值加起来为 0 0 0

e a s y − v e r s i o n easy-version easyversion:用前缀和处理,如果 s u m [ r ] − s u m [ l − 1 ] = = 0 sum[r] - sum[l - 1] == 0 sum[r]sum[l1]==0 直接输出 0 0 0 次就可以,如果区间里元素个数为奇数,那么可以证明(具体证明可以看cf题解证明一定存在一个数,删除后保证整个区间为 0 0 0 ,偶数的情况就先删除 l l l ,再按照奇数情况处理。

h a r d − v e r s i o n hard-version hardversion:和简单版本的区别就是要输出删除的位置,稍做分析我们就知道删除一个位置后,后边的和会翻转,所以我们需要找到一个位置 s u m [ r ] − s u m [ x − 1 ] = s u m [ x ] − s u m [ l − 1 ] sum[r] - sum[x - 1] = sum[x] - sum[l-1] sum[r]sum[x1]=sum[x]sum[l1],可以得到一个式子 s u m [ r ] + s u m [ l − 1 ] = s u m [ x ] + s u m [ x − 1 ] sum[r] + sum[l-1]=sum[x] + sum[x-1] sum[r]+sum[l1]=sum[x]+sum[x1],这样我们就可以进行二分了,具体看代码qwq

AC代码

e a s y − v e r s i o n easy-version easyversion

#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <map>
#include <vector>
#include <queue>

#define x first
#define y second

using namespace std;

typedef long long ll;
const int N = 300010;

int T, n, q;
int a[N]; 

int main()
{
	cin >> T;
	while (T --) {
		cin >> n >> q;
		string s;
		cin >> s;
		for (int i = 0; i < s.size(); i ++) {
			if (s[i] == '-') a[i + 1] = -1;
			else a[i + 1] = 1;
			if ((i + 1) & 1) a[i + 1] *= 1;
			else a[i + 1] *= -1;
		}
		for (int i = 1; i <= n; i ++) {
			a[i] += a[i - 1];
		}
		
		while (q --) {
			int l, r;
			cin >> l >> r;
			if (a[r] - a[l - 1] == 0) cout << 0 << endl;
			else if ((r - l + 1) & 1) cout << 1 << endl;
			else cout << 2 << endl;
		}
	}
}

h a r d − v e r s i o n hard-version hardversion

#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <map>
#include <vector>
#include <queue>

#define x first
#define y second

using namespace std;

typedef long long ll;
const int N = 300010;

int T, n, q;
int a[N];
vector<int> v[6 * N];

int main()
{
	cin >> T;
	while (T --) {
		cin >> n >> q;
		string s;
		cin >> s;
		for (int i = 0; i < n; i ++) {
			a[i + 1] = a[i] + ((i & 1) ? 1 : -1) * ((s[i] == '+' ? 1 : -1));
			v[a[i + 1] + a[i] + 2 * n].push_back(i + 1);
		}
		
		while (q --) {
			int l, r;
			cin >> l >> r;
			if (a[r] - a[l - 1] == 0) cout << 0 << endl;
			else if ((r - l + 1) & 1) {
				puts("1");
				int x = a[r] + a[l - 1] + 2 * n;
				int t = *lower_bound(v[x].begin(), v[x].end(), l);
				cout << t << endl;
			}
			else {
				puts("2");
				cout << l << " ";
				int x = a[r] + a[l] + 2 * n;
				int t = *lower_bound(v[x].begin(), v[x].end(), l + 1);
				cout << t << endl;
			}
		}
		
		for (int i = 1; i <= n; i ++) v[a[i] + a[i - 1] + 2 * n].clear();
	}
}

——END

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

半碗无糖蓝莓冻

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值