Codeforces Round #841 (Div. 2) and Divide by Zero 2022
题目大意
给定一个数组,求满足所有元素异或的结果有偶数个因子的子数组的个数。本题将0视作有奇数个因子。
解题思路
直接求不好求,我们可以求异或结果有奇数个因子的子数组。
对于一个数,我们可以将其分解为\(p_1^{c_1}p_2^{c_2}\cdots p_n^{c_n}\),\(p_i\)均为质数。
其因子的个数为\((c_1 + 1)(c_2 + 2)\cdots (c_n + 1)\),要使其乘积为奇数,则所有的\(c_i\)都应为奇数,则该数为完全平方数。
在题目给定的范围中,完全平方数并不多,可以暴力枚举。
注意n以内的数字异或结果\(\le 2*n\)
可以用前缀异或的方式快速判断是否有子数组的异或结果为特定的数字。
具体见代码
参考代码
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
vector<int> squ;
int a[N];
int cnt[N * 4];//记录前缀异或出现过的数据,注意数组大小
#define ll long long
void work()
{
int n;
cin >> n;
ll ans = 1ll * n * (n + 1) / 2;
for (int i = 1; i <= n; ++i)
{
cin >> a[i];
a[i] ^= a[i - 1];
for (auto j : squ)
ans -= cnt[a[i] ^ j];
//关键在这里,若a[i] ^ j的结果出现过,我们记a[k] = a[i] ^ j,k < i
//a[k] ^ a[k] = a[j] ^ a[k] ^ j
//即a[j] ^ a[k] = j
//即从下标k到j的元素异或结果为j,那么改子数组不应作为答案的一部分,需要减去
++cnt[a[i]];//记录前缀异或
}
cout << ans << endl;
for (int i = 1; i <= n; ++i)
--cnt[a[i]];
}
int main()
{
for (int i = 0; i * i < N * 2; ++i)
{
squ.push_back(i * i);
}
++cnt[0];
ios::sync_with_stdio(0);
cout.tie(0);cin.tie();
int T;
cin >> T;
while (T--)
{
work();
}
return 0;
}
标签:Even,cnt,奇数,int,Subarrays,因子,异或,数组
From: https://www.cnblogs.com/hetailang/p/17009818.html