CF1731C

题意:给定n个大小为n以内的数(n<=2e5),求有多少对lr使得区间[l,r]的按位异或值的因数数量为偶数(l<=r)
首先不难想到因数都是成对的,除了一种情况:数字为平方数。因此因数数量为奇数时说明异或结果必然为平方数
考虑到数字范围只有2e5,并且异或后的最大值最多也就不到2* n,所以我们想到可以循环枚举这些数
然后就是异或的性质,一个数异或他本身等于0,因此异或也可以进行前缀和操作,类似于普通的前缀和,sum[i]^sum[j-1] (i>j)就是j到i区间的异或值,这点是解题的关键
如果a ^ b=c,那么a=b^c。所以我们可以循环所有的平方数,对于每个sumi都寻找在i之前有多少个符合条件的sumj并加上
最后用lr的总对数减去即可
一个点是,在记录每个sum的出现次数时,要把cnt[0]初始化为1,因为对于所有L为1的区间在计算区间异或时都是sum[i]^sum[0],少统计sum[0]会导致区间统计数量不正确

#include<bits/stdc++.h>
#define endl "\n"
#define int long long
using namespace std;
const int maxn=2e5+10;
int a[maxn],sum[maxn];
int cnt[1000005];
int n;
void youlinaixu()
{
	for(int i=0;i<=n*2;i++) cnt[i]=0;
	cin>>n;
	int ans=n*(n-1)/2+n;
	cnt[0]++;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		sum[i]=sum[i-1]^a[i];
		for(int j=0;j<=650;j++)
		{	
			ans-=cnt[(j*j)^sum[i]];
		}
		cnt[sum[i]]++;
	}
	cout<<ans<<endl;
}
signed main()
{
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int t=1;
	cin>>t;
	while(t--)
	{
	    youlinaixu();
    }
    return 0;
}
posted @ 2025-05-30 18:18  miku今天吃什么  阅读(8)  评论(0)    收藏  举报