Codeforces Round #841 (Div. 2) C. Even Subarrays

文章目录


C. Even Subarrays
严格鸽题解
多向大佬学习

题意

题意:给我们一个数组a问我们有几个子区间的异或和满足因子个数是偶数。

思路

思路:首先因子的话都是成对出现的,那什么情况下是奇数呢,就是这个数是平方数的时候,那么此时因子有一对两个数是相同的,所以就肯定是奇数。

因次我们现在的目的就要找子区间异或和等于平方数的个数,然后用总的减去异或和等于平方数的子区间的个数即可。

首先我们看一下前缀和异或和 p r e [ i ] = a [ 1 ] ⨁ a [ 2 ] ⨁ a [ 3 ] . . . a [ i ] pre[i] = a[1] \bigoplus a[2] \bigoplus a[3] ... a[i] pre[i]=a[1]a[2]a[3]...a[i]然后呢,我们想求一个区间的异或和也就是 a [ L ] ⨁ a [ L + 2 ] ⨁ a [ L + 3 ] . . . a [ R ] a[L] \bigoplus a[L+2] \bigoplus a[L+3] ... a[R] a[L]a[L+2]a[L+3]...a[R]那么这个区间异或怎么求呢,我们可以同过异或运算的性质来求 x ⨁ 0 = x x ⨁ x = 0 x\bigoplus0=x \quad x\bigoplus x = 0 x0=xxx=0也就是 p r e [ R ] − p r e [ L − 1 ] = ( a [ 1 ] ⨁ a [ 2 ] ⨁ a [ 3 ] . . . a [ L − 1 ] ) ⨁ a [ L + 1 ] ⨁ a [ L + 2 ] . . . a [ R ] ⨁ ( a [ 1 ] ⨁ a [ 2 ] ⨁ a [ 3 ] . . . a [ L − 1 ] ) pre[R] - pre[L-1] = (a[1] \bigoplus a[2] \bigoplus a[3] ... a[L-1]) \bigoplus a[L+1] \bigoplus a[L+2] ... a[R] \bigoplus (a[1] \bigoplus a[2] \bigoplus a[3] ... a[L-1]) pre[R]pre[L1]=(a[1]a[2]a[3]...a[L1])a[L+1]a[L+2]...a[R](a[1]a[2]a[3]...a[L1])那么此时的前面的小括号里的部分和后面的小括号部分就抵消了,整个式子就等于 a [ L ] ⨁ a [ L + 2 ] ⨁ a [ L + 3 ] . . . a [ R ] a[L] \bigoplus a[L+2] \bigoplus a[L+3] ... a[R] a[L]a[L+2]a[L+3]...a[R]

然后我们得到上面的结论之后我们就可以枚举 p r e [ R ] pre[R] pre[R]看有几个 p r e [ R ] ⨁ p r e [ L − 1 ] = n u m pre[R] \bigoplus pre[L-1] = num pre[R]pre[L1]=num这里的num为平方数上个式子也可以写成 p r e [ L − 1 ] = p r e [ R ] ⨁ n u m pre[L-1] = pre[R] \bigoplus num pre[L1]=pre[R]num。然后我们计一下个数最后用总的减去即可。
注意 L − 1 L-1 L1是可以等于0的所以我们mp[0]初始值赋成1

AC代码

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N = 1e6 + 10;
int mp[N], a[N];

void solve()
{
     int n;
     cin >> n;
     for (int i = 1; i <= n; i++)
          cin >> a[i];
     mp[0] = 1;
     int ans = 0, pre = 0;
     for (int i = 1; i <= n; i++)
     {
          pre ^= a[i];
          for (int x = 0; x * x <= 2 * n; x++)
          {
               int num = x * x;
               ans += mp[pre ^ num];
          }
          mp[pre]++;
     }
     cout << n * (n + 1) / 2 - ans << endl;
     // memset(mp, 0, sizeof mp);
     for (int i = 0; i < 2 * n; i++)
          mp[i] = 0;
}

signed main()
{
     ios::sync_with_stdio(false);
     cin.tie(0);
     cout.tie(0);
     int T;
     cin >> T;
     while (T--)
     {
          solve();
     }
     return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值