Even Subarrays(数论问题)
题目描述:
You are given an integer array \(a_1,a_2,…,a_n (1≤a_i≤n).\)
Find the number of subarrays of a whose XOR has an even number of divisors. In other words, find all pairs of indices \((i,j) (i≤j)\) such that \(a_i⊕a_{i+1}⊕⋯⊕a_j\) has an even number of divisors.
For example, numbers \(2, 3, 5\) or \(6\) have an even number of divisors, while \(1\) and \(4\) — odd. Consider that 0 has an odd number of divisors in this task.
Here XOR (or \(⊕\)) denotes the bitwise XOR operation.
Print the number of subarrays but multiplied by 2022... Okay, let's stop. Just print the actual answer.
输入描述:
Each test contains multiple test cases. The first line contains the number of test cases \(t (1≤t≤10^4)\). Description of the test cases follows.
The first line of each test case contains a single integer \(n (2≤n≤2⋅10^5)\) — the length of the array \(a\).
The second line contains n integers \(a_1,a_2,…,a_n (1≤a_i≤n)\).
It is guaranteed that the sum of \(n\) over all test cases does not exceed \(2⋅10^5\).
输入描述:
For each test case, print the number of subarrays, whose XOR has an even number of divisors.
样例:
input:
4
3
3 1 2
5
4 2 1 5 3
4
4 4 4 4
7
5 7 3 7 1 7 3
output:
4
11
0
20
Note:
In the first test case, there are \(4\) subarrays whose XOR has an even number of divisors: \([3], [3,1], [1,2], [2]\).
In the second test case, there are \(11\) subarrays whose XOR has an even number of divisors: \([4,2], [4,2,1], [4,2,1,5], [2], [2,1], [2,1,5], [2,1,5,3], [1,5,3], [5], [5,3], [3]\).
In the third test case, there is no subarray whose XOR has an even number of divisors since XOR of any subarray is either \(4\) or \(0\).
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
int T = 1;
LL n;
void solve()
{
scanf("%lld", &n);
vector<int> a(n), b(2 * n); // 开两个vector,一个用于存数组,一个用于存某个数出现的次数
a.clear(), b.clear();
for (int i = 0; i < n; i++)
{
scanf("%d", &a[i]);
}
LL cnt = 0; // 存储异或和的因数为奇数个的数的个数
int t = 0;
b[t]++; // a[0] ^ a[0]为0
for (int i = 0; i < n; i++)
{
t ^= a[i];
// n个数可能的异或最大值肯定小于2 * n
// 判断某个数的因数是否为奇数的条件就是判断其是否是完全平方数
for (LL j = 0; j * j < 2 * n; j++)
{
// 一个数 t 异或一个完全平方数 p 的结果 x,该结果 x 异或 t 的结果必定是那个完全平方数 p,只要 x 存在,则 j * j 必存在
// t 是 1-i 的异或和,假设 p 是 j-i 的异或和,则 x 就是 1-(j-1) 的异或和,所以 x ^ p = t,所以此时只需要判断 x 出现过的次数即可
if ((t ^ (j * j)) < 2 * n)
{
cnt += b[t ^ (j * j)]; // cnt 加上这个数出现过的次数
}
}
b[t]++; // t的出现的次数加一
}
LL ans = (n * (n + 1) / 2) - cnt; // 总共的个数减去不成立的个数即为成立的个数
printf("%lld\n", ans);
}
int main()
{
// ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
scanf("%d", &T);
while (T--)
{
solve();
}
return 0;
}