C. Sasha and a Bit of Relax
题意:
给定大小为 n 的数列,问有多少对 (l, r) 满足当 mid = (l+r-1) 时,Al^Al+1……^Amid = Amid+1^Amid+2……^Ar(^表示异或)。
题解:
根据前缀和的原理,用一个数组保存异或前缀。
题目例子:
数组下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
例子数据 | 0 | 3 | 2 | 2 | 3 | 7 | 6 |
异或前缀 | 0 | 3 | 1 | 3 | 0 | 7 | 1 |
那么有什么用呢?想一下,异或的原理:a^c=b, b^c=a。
数组下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
例子数据 | 0 | 3 | 2 | 2 | 3 | 7 | 6 |
异或前缀 | 0 | 3 | 1 | 3 | 0 | 7 | 1 |
很容易看出来,如果两个相同异或前缀之间下标相差偶数,即可满足上面的条件。
然后我们只需数一下满足条件的有多少个即可。
而且,根据原理,分别计算奇偶情况的话,只需扫一遍即可,时间复杂度O(N)。
出现一次就加上 vis[num],然后vis[num]++。
为什么呢?因为分了奇偶,每次两个相同的异或前缀下标差必为偶数,也就是出现一次,就可以和前面已经出现的任意一个组为一对。
代码:
#include <iostream>
using namespace std;
int n;
int a, b;
long long ans;
int dp[2][1<<20];
int main(){
scanf("%d", &n);
dp[0][0] = 1;
for(int i = 1; i <= n; ++i){
scanf("%d", &a);
b^=a;
ans+=dp[i%2][b];
++dp[i%2][b];
}
printf("%I64d", ans);
return 0;
}
吐槽:
凌晨场扛不住啊,签个到B题都没调出来就跑去睡觉了,这才补掉C。