codeforces 1438 E. Yurii Can Do Everything (暴力)
题目链接:https://codeforces.com/contest/1438/problem/E
根据题目性质,答案不会太大
枚举左端点 \(l\), 令 \(k\) 为 \(a_l\) 的最高位,那么可能合法的右端点 \(r\) 一定在区间和小于 \(2^{k + 1}\) 的区间内,暴力寻找右端点 \(r\) 即可
正着做完以后再反着来一遍,去重即可
而每个右端点不会被扫描超过 \(lg(a_r)\) 次,因为对于每一位来说,如果这一位已经被扫到过了,那么如果又被扫到,区间和必定大于等于 \(2^{k+1}\)
于是时间复杂度位 \(O(n*log(a_i))\)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> P;
const int maxn = 200010;
int n;
ll a[maxn], sum[maxn];
map<P, bool> mp;
ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }
int main(){
n = read();
for(int i = 1 ; i <= n ; ++i) a[i] = read(), sum[i] = sum[i - 1] + a[i];
int ans = 0;
for(int i = 1 ; i <= n - 2 ; ++i){ // 枚举 l
int k;
for(int j = 30 ; j >= 0 ; --j){ // 找到最高位 1
if((a[i] >> j) & 1){
k = j;
break;
}
}
for(int j = i + 2 ; j <= n ; ++j){
if(sum[j - 1] - sum[i] >= (1 << (k + 1))) break;
if(sum[j - 1] - sum[i] == (a[i] ^ a[j])) {
// printf("%d %d %lld %lld\n", i, j, sum[j - 1] - sum[i], a[i] ^ a[j]);
++ans;
mp[make_pair(i, j)] = true;
}
}
}
// printf("\n", ans);
// for(int i = 1 ; i <= n ; ++i){
// for(int j = i + 2 ; j <= n ; ++j){
// if(mp.find(make_pair(i, j)) != mp.end()){
// printf("%d %d\n", i, j);
// }
// }
// }
// 倒着做
for(int i = n ; i >= 3 ; --i){ // 枚举 l
int k;
for(int j = 30 ; j >= 0 ; --j){ // 找到最高位 1
if((a[i] >> j) & 1){
k = j;
break;
}
}
for(int j = i - 2 ; j >= 1 ; --j){
if(sum[i - 1] - sum[j] >= (1 << (k + 1))) break;
if(sum[i - 1] - sum[j] == (a[i] ^ a[j]) && (mp.find(make_pair(j, i)) == mp.end())) { //
// printf("%d %d %lld %lld\n", j, i, sum[i - 1] - sum[j], a[i] ^ a[j]);
++ans;
}
}
}
printf("%d\n", ans);
return 0;
}