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;
}

浙公网安备 33010602011771号