大意:给出一个由N个数字组成的序列A,Q次询问一个随机区间 l ,r 将此区间的数连乘起来,问得到的是不是一个立方数
题解: 对每一个数进行质因数分解并存下前i个数乘起来后的每个质因数数量状态(前缀思想),看到大佬都用了一种 随机打表和异或 的操作将这种状态压缩成一个非常大的数,使得查询的复杂度直接降到O(1)
#include<bits/stdc++.h>
#define lowbit(x) ((x)&(-x))
//#define int long long
using namespace std;
const int N=1e7+10;
int m,n,cnt[N+10];
u64 ran[N+10][3],num=0,h[N+10],mod=1e9+7;
using u64 = unsigned long long;
std::mt19937_64 rng;
signed main()
{
int i,j,x;
for(i=1; i<N; i++)
for(j=0; j<3; j++)
ran[i][j]=rng();/*对每一个素数所有的数量状态赋一个随机值,打好表*/
/*num表示乘上前i个数后,所有质因子数量状态的异或结果*/
for(i=1; i<N; i++) num^=ran[i][0];/*刚开始所有质因数的数量状态都为0*/
h[0]=num;
scanf("%d%d",&n,&m);
for(i=1; i<=n; i++)
{
scanf("%d",&x);
for(j=2; j*j<=x; j++)
{
if(x%j==0)
{
num^=ran[j][cnt[j]];
/*这里j这个质因数的数量状态改变了,所以先把老的状态擦除,直接异或这个老状态的随机值*/
while(x%j==0) cnt[j]=(cnt[j]+1)%3,x/=j;
num^=ran[j][cnt[j]];/*加上新的状态*/
}
}
if(x>1)
{
num^=ran[x][cnt[x]];
cnt[x]=(cnt[x]+1)%3;
num^=ran[x][cnt[x]];
}
h[i]=num;
}
while(m--)
{
int l,r;
scanf("%d%d",&l,&r);
l--;
if(h[l]==h[r]) printf("Yes\n");
else printf("No\n");
}
return 0;
}