P10724 [GESP202406 七级] 区间乘积

今天来写一篇困扰了我好久的题的题解

借鉴了洛谷@T0mle大佬的题解

题目

传送门

思路

完全平方数是什么?

一个正整数 x 为完全平方数当且仅当存在一个正整数 y 使得 x=y*y。但是,我们要知道完全平方数还有一个性质,那就是他一定由偶数个质数构成

如何利用这个性质?

我们观察到题目的数据范围:1<=a[i]<=30,而我们30以内的质数只有10个,那么我们可以用二进制来表示状态,0表示偶数,1表示奇数,每一位是代表一个质数的奇偶性。

这个二进制状态有什么用?

我们要求的是区间的乘积,那么我们分情况可以发现实际上他进行的就是一个异或运算。那么我们就可以定义一个异或前缀和,只要这个区间的1可以相互抵消,[l,r]中数的乘积才是完全平方数。
我们可以定义一个sum数组,每次进行完前缀和后加上相同的数,然后再更新。可以加上相同的数是因为这时候我们的1可以相互抵消。

ans记得开long long

代码

有注释

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,zs[15]={2,3,5,7,11,13,17,19,23,29};
long long ans=0;
int b[N],sum[N];
void ycl(){
	for(int i=1;i<=30;i++){
		int i1=i;
		for(int j=0;j<10;j++){
			while(i1%zs[j]==0){//如果可以取余为0 
				b[i]^=1<<j;//每个数的质数的奇偶性 
				i1/=zs[j];
			}
		}
	}
	return;
}
int main(){
	std::ios::sync_with_stdio(false);//关闭输入输出流 
	std::cin.tie(0);
	std::cout.tie(0);
	cin>>n;
	ycl();//预处理 
	int p=0;
	sum[0]=1;
	for(int i=1;i<=n;i++){
		int a;//可以不用数组了 
		cin>>a;
		p^=b[a];//异或前缀和 
		ans+=sum[p];//加上前面已经有的 
		sum[p]++;//更新 
	}
	cout<<ans;
	return 0;
} 

无注释

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,zs[15]={2,3,5,7,11,13,17,19,23,29};
long long ans=0;
int b[N],sum[N];
void ycl(){
	for(int i=1;i<=30;i++){
		int i1=i;
		for(int j=0;j<10;j++){
			while(i1%zs[j]==0){
				b[i]^=1<<j;
				i1/=zs[j];
			}
		}
	}
	return;
}
int main(){
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	std::cout.tie(0);
	cin>>n;
	ycl();
	int p=0;
	sum[0]=1;
	for(int i=1;i<=n;i++){
		int a;
		cin>>a;
		p^=b[a];
		ans+=sum[p];
		sum[p]++;
	}
	cout<<ans;
	return 0;
} 

完结撒花

posted @ 2026-09-02 23:23  陈晨2011  阅读(4)  评论(0)    收藏  举报