这是这个问题的简单版本。唯一不同的是,在这个版本中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