C2. Sheikh

Problem - C2 - Codeforces

题意:给定你一个数组,给定m个查询Li,Ri,要求找到每个查询区间中a[l]+a[l+1]+...+a[r]-a[l]^a[l+1]^...a[r]最大值的长度最小的区间的左右下标

思路:暴力的做法是枚举左端点,利用右端点在右半部分是单调的特性二分从而找到最小的区间。但是这样做会导致hard版本tle。

于是我们想到探究这个式子的特性:左右两边可删去的非零数字是有限的,且这个数的数量级比较小,我们想到,左右两边如果总共删除超过60个数就会必定导致结果改变(具体的讲,是会变小)。于是我们维护非零数字的数量,以及它们之间的相对位置关系,再进行暴力枚举,就可以得出答案了

至于为什么是60个数,原因在于每一位上最多重复删两次(ps:实际上31个数就足够了,因为我们只需要有一位上有重复,但是防止边界问题,就留足余量啦)。

注意左右都必须是60,才能覆盖所有情况

注意特殊情况等于0时的特判(此时能删除所有数只保留一个就行了)

注意记录相对关系时的边界条件特判

EAZY版的做法(实际上hard版与eazy版之间hard是可以套在eazy上的)

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<string>
#include<bitset>
#include<cmath>
#include<array>
#include<atomic>
#include<sstream>
#include<stack>
#include<iomanip>
//#include<bits/stdc++.h>

//#define int ll
#define IOS std::ios::sync_with_stdio(false);std::cin.tie(0);
#define pb push_back
#define endl '\n'
#define x first
#define y second
#define Endl endl
#define pre(i,a,b) for(int i=a;i<=b;i++)
#define rep(i,b,a) for(int i=b;i>=a;i--)
#define si(x) scanf("%d", &x);
#define sl(x) scanf("%lld", &x);
#define ss(x) scanf("%s", x);
#define YES {puts("YES");return;}
#define NO {puts("NO"); return;}
#define all(x) x.begin(),x.end()

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<int, PII> PIII;
typedef pair<char, int> PCI;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<ll, ll> PLL;
const int N = 500010, M = 2 * N, B = N, MOD = 998244353;
const double eps = 1e-7;
const int INF = 0x3f3f3f3f;
const ll LLINF = 0x3f3f3f3f3f3f3f3f;

//int dx[4] = { -1,0,1,0 }, dy[4] = { 0,1,0,-1 };
int dx[8] = { 1,2,2,1,-1,-2,-2,-1 }, dy[8] = { 2,1,-1,-2,-2,-1,1,2 };
int n, m, k;
int a[N];
ll sum[N];
int pxor[N];
int bkidx[55], ftidx[55];
int heap[N][55];

ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; }
ll lowbit(ll x) { return x & -x; }
ll qmi(ll a, ll b, ll MOD) {
	ll res = 1;
	while (b) {
		if (b & 1) res = res * a % MOD;
		a = a * a % MOD;
		b >>= 1;
	}
	return res;
}

inline void init() {}

ll f(int l, int r)
{
	return sum[r] - sum[l - 1] - (pxor[r] ^ pxor[l-1]);
}

bool check(int l,int r,ll c)
{
	return f(l, r) == c;
}

void slove()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++) cin >> a[i];

	for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + a[i];
	for (int i = 1; i <= n; i++) pxor[i] = pxor[i - 1] ^ a[i];

	while (m--)
	{
		int L, R;
		cin >> L >> R;
		PII ans = { L,R };
		ll k = f(L, R);
		
		for (int i = L; i <= R; i++)
		{
			int l = i, r = R + 1;
			while (l < r)
			{
				int mid = l + r >> 1;
				if (check(i, mid, k))r = mid;
				else l = mid + 1;
			}
			if (r == R + 1)continue;
			if (r - i < ans.y - ans.x) ans = { i,r };
		}
		cout << ans.x << ' ' << ans.y << endl;
	}
	return;
}

signed main()
{
	//IOS;
	int _ = 1;
	si(_);
	init();
	while (_--)
	{
		slove();
	}
	return 0;
}
/*
1
4 1
0 12 8 3
1 4

*/

 HARD版

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<string>
#include<bitset>
#include<cmath>
#include<array>
#include<atomic>
#include<sstream>
#include<stack>
#include<iomanip>
//#include<bits/stdc++.h>

//#define int ll
#define IOS std::ios::sync_with_stdio(false);std::cin.tie(0);
#define pb push_back
#define endl '\n'
#define x first
#define y second
#define Endl endl
#define pre(i,a,b) for(int i=a;i<=b;i++)
#define rep(i,b,a) for(int i=b;i>=a;i--)
#define si(x) scanf("%d", &x);
#define sl(x) scanf("%lld", &x);
#define ss(x) scanf("%s", x);
#define YES {puts("YES");return;}
#define NO {puts("NO"); return;}
#define all(x) x.begin(),x.end()

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<int, PII> PIII;
typedef pair<char, int> PCI;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<ll, ll> PLL;
const int N = 500010, M = 2 * N, B = N, MOD = 998244353;
const double eps = 1e-7;
const int INF = 0x3f3f3f3f;
const ll LLINF = 0x3f3f3f3f3f3f3f3f;

//int dx[4] = { -1,0,1,0 }, dy[4] = { 0,1,0,-1 };
int dx[8] = { 1,2,2,1,-1,-2,-2,-1 }, dy[8] = { 2,1,-1,-2,-2,-1,1,2 };
int n, m, k;
int a[N];
ll sum[N];
int pxor[N];
int nex[N], pre[N];
int cnt[N];

ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; }
ll lowbit(ll x) { return x & -x; }
ll qmi(ll a, ll b, ll MOD) {
	ll res = 1;
	while (b) {
		if (b & 1) res = res * a % MOD;
		a = a * a % MOD;
		b >>= 1;
	}
	return res;
}

inline void init() {}

ll f(int l, int r)
{
	return sum[r] - sum[l - 1] - (pxor[r] ^ pxor[l-1]);
}

bool check(int l,int r,ll c)
{
	return f(l, r) == c;
}

void slove()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++) cin >> a[i];

	for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + a[i];
	for (int i = 1; i <= n; i++) pxor[i] = pxor[i - 1] ^ a[i];
	for (int i = 1; i <= n; i++) cnt[i] = cnt[i - 1] + (a[i] != 0);

	nex[n] = INF, pre[1] = -INF;
	for (int i = 2; i <= n; i++) {
		if (a[i - 1])pre[i] = i - 1;
		else pre[i] = pre[i - 1];
	}
	for (int i = n-1; i >= 1; i--) {
		if (a[i + 1])nex[i] = i + 1;
		else nex[i] = nex[i + 1];
	}

	while (m--)
	{
		int L, R;
		cin >> L >> R;
		ll k = f(L, R);
		PII ans = { L,R };
		if (cnt[R] - cnt[L - 1] == 0)ans = { L,L };
		else if (cnt[R] - cnt[L] <= 60)
		{
			
			if (!a[L]) L = nex[L];
			if (!a[R])R = pre[R];
			for(int i=L;i<=R;i=nex[i])
				for (int j = i; j <= R; j = nex[j])
				{
					if (f(i, j) == k && j - i < ans.y - ans.x) {
						ans = { i,j };
					}
				}
		}
		else {
			vector<int> le, ri;
			if (!a[L]) L = nex[L];
			if (!a[R])R = pre[R];
			for (int i = L, cnt = 0; i <= R && cnt < 60; i = nex[i], cnt++)
				le.push_back(i);
			for (int i = R, cnt = 0; i >= L && cnt < 60; i = pre[i], cnt++)
				ri.push_back(i);

			for(int& i:le)
				for (int& j : ri)
				{
					if (i > j)continue;
					if (f(i, j) == k && j - i < ans.y - ans.x) {
						ans = { i,j };
					}
				}
		}
		cout<< ans.x << ' ' << ans.y << Endl;
	}
	return;
}

signed main()
{
	//IOS;
	int _ = 1;
	si(_);
	init();
	while (_--)
	{
		slove();
	}
	return 0;
}
/*
1
7 7
0 1 0 1 0 1 0
1 7
3 6
2 5
1 4
4 7
2 6
2 7

*/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值