C1. Sheikh (Easy version)(双指针 + 异或与加法的关系)

该编程问题要求找到一个整数数组中,具有最大代价(子段和减去子段异或)的子段,并确保这个子段是最短的。使用双指针技术,从左到右移动右指针以扩大子段,直到找到最大代价,然后移动左指针来寻找最短的子段。代码示例给出了如何实现这一过程。
摘要由CSDN通过智能技术生成

Problem - C1 - Codeforces

这是这个问题的简单版本。唯一不同的是,在这个版本中q = 1。给定一个整数数组a1 a2。,一个数组[2,r], 1 <l<r <n的子段的代价为f(l,r) = sum(l, r) - xor(l, r),其中sum(l, r) = a2+ a2+1 ..+ ar和xor (l, r) = aΦα2 + 1 ...Φα,(Φ代表bitwise XOR)。n.需要找到f(L, r)最大值的子段[Z, n], L SrR,如果有几个答案,则需要在其中找到长度最小的子段,即r - L + 1的最小值。您将有q = 1的查询。每个查询由一对数字Li, R给出,其中1 < Li < R, <输入每个测试由多个测试用例组成。第一行包含一个整数(1 t 104)——测试用例的数量。测试用例的描述如下。每个测试用例的第一行包含两个整数n和q (1 < n < 105, q = 1)——数组的长度和查询的数量。每个测试用例的第二行包含n个整数a1, a2,…,一个(0≤a, < 10°)-数组元素。每个测试用例下q行的第i行包含两个整数L和R(1≤Li S R≤n)——我们需要在其中找到线段的边界。它保证所有测试用例的n和不超过2 - 105。保证L1 =1, R1 =n。输出对于每个测试用例,打印q对Li <r r的数字,使f(l, r)值最大,其中r-l+1长度最小。如果有几个正确答案,打印其中任何一个。

Example

input

Copy

 

6

1 1

0

1 1

2 1

5 10

1 2

3 1

0 2 4

1 3

4 1

0 12 8 3

1 4

5 1

21 32 32 32 10

1 5

7 1

0 1 0 1 0 1 0

1 7

output

Copy

1 1
1 1
1 1
2 3
2 3
2 4

题解:
根据异或的性质,两个数异或,一定小于两个数相加

那么区间数相加 - 区间数异或和一定是最大值

我们只需要用双指针截取最短区间即可

 

#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<queue>
#include<set>
#include<cstdio>
using namespace std;
//#define int long long
const int N = 2e6 + 10;
typedef pair<int, int> PII;
typedef long long ll;
ll a[N];
ll s[N],x[N];
void solve() 
{
	int n,q;
	cin >> n >> q;
	for(int i = 1;i <= n;i++)
	{
		cin >> a[i];
		s[i] = s[i - 1] + a[i];
		x[i] = x[i - 1] ^ a[i];
	}
	int l,r;
	cin >> l >> r;
	PII ans = {1,n + 1};
	l = 1,r = 1;
	ll p = s[n] - x[n];
	while(l <= n)
	{
		while(r <= n&&s[r] - s[l-1] - (x[r]^x[l-1]) < p)
		{
			r++;
		}
		if(r > n)
		break;
		while(l <= n&&s[r] - s[l-1] - (x[r]^x[l-1]) == p)
		{
			l ++;
		} 
		if(l > r)//可能会存在单个位置是最大值的情况,所以特判一下
		r = l - 1;
		if(ans.second - ans.first > r -l +1)
		ans = {l-1,r}; 
	} 
	cout << ans.first<<" "<<ans.second<<"\n";
}
 
//1 2 4
signed main() 
{
//	ios::sync_with_stdio(0);
//	cin.tie(0);cout.tie(0);
	int t = 1;
//	cin >> t;
scanf("%d",&t);
	while (t--) 
	{
		solve();
	}
	return 0;
}
//1 1 1 0 1
 
//1 1 1 0 1
//1 1 1 0 1
//1 1 1 0 1
//0 1 1 1 1
//0 1 1 1 1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值