CF1438E
题解思路:
我们会发现一个性质:满足条件的区间不会很多。
因为满足条件的数很少,所以我们就可以用暴力。
我们先假设,这个区间是以
对于这样的情况下,那么我们就暴力求满足条件的区间就可以了。
先对于
终止条件是什么呢?
我们假设最高位是第 k 位,那么
所以我们就暴力枚举
然后再倒着,对于
证明时间复杂度:
假设这是以第
我们假设二进制最高位为
那么对于每个下标累加和是多少:
那么这些数的累加和算下来他就是
有
AC CODE:
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
#include <cstdio>
#include <set>
using namespace std;
typedef long long ll;
const int N = 200010;
int n;
int a[N];
set <pair <int , int>> s;//用set去重
int log2 (int x) {//求log2
int cnt = 0;
while (x) {
++ cnt;
x >>= 1;
}
return cnt;
}
void solve (bool op) {//0代表正着,1代表倒着
vector <int> pre (n + 10);
for (int i = 1; i <= n; ++ i)
pre[i] = pre[i - 1] + a[i];//求前缀和
for (int i = 1; i <= n - 2; ++ i) {
ll sum = a[i + 1];
int x = log2 (a[i]) + 1;
for (int j = i + 2; j <= n; ++ j) {
if ((a[i] ^ a[j]) == pre[j - 1] - pre[i]) {//看看这个区间是否满足这个性质
if (!op) s.insert ({i , j});//正着直接插入
else s.insert ({n - j + 1 , n - i + 1});//倒着
}
if ((sum + a[i]) > (1ll << x)) break;//超过了范围,break
sum += a[j];
}
}
}
int main() {
scanf ("%d" , &n);
for (int i = 1; i <= n; ++ i)
scanf ("%d" , &a[i]);
solve (0);//正着来
reverse (a + 1, a + 1 + n);
solve (1);//倒着来
printf ("%d\n" , (int)s.size());//输出答案
return 0;
}
码字不易,求赞!