思路
莫队 。
哈希。
把 质因数分解,指数模 。直接乘过大,考虑哈希。每个质数的指数和都因为 的倍数。
即:所有数的出现次数和是否都为 的倍数。
法一:前缀和。给每个质数随机 ,,做前缀和。如果是完全立方数可推出 。因为对 取模,所以 可看作从 中随机。显然只做一次是不行的,重复 次。可以大概认为单次正确率为 ,一道题正确率 , 是测试点数。
法二:异或。给每个质数随机 到 共 个值,令 。从前往后,如果当前 有质因数 且 在 前已经出现 次, 对 取模, 异或上 。做前缀异或和,如果是完全立方数可推出 。因为是异或,所以错误率极低。
法一适合 较大,法二适合 较小,代码用法二。
另外,既然不用莫队,可以把复杂度优化到 ,筛质数的时候记录 表示 最小的质因数。
code
int n,m;
int pre[maxn],cnt;
int g[maxn],f[maxn];
bool vis[maxn];
int val[maxn][3],num[maxn];
void s(int n){
for(int i=2;i<=n;i++){
if(!vis[i]){
pre[++cnt]=i;g[i]=i;
val[i][0]=rand()*rand()%inf;
val[i][1]=rand()*rand()%inf;
val[i][2]=val[i][0]^val[i][1];
}
for(int j=1;j<=cnt&&i*pre[j]<=n;j++){
vis[i*pre[j]]=1;g[i*pre[j]]=pre[j];
if(i%pre[j]==0)break;
}
}
}
void work(){
srand(time(0));
n=read();s(maxn-10);m=read();
for(int i=1;i<=n;i++){
int x=read();
while(g[x]){
f[i]^=val[g[x]][num[g[x]]%3];
num[g[x]]++;
x/=g[x];
}
// cout<<f[i]<<" ";
f[i]^=f[i-1];
}
while(m--){
int u=read(),v=read();
if((f[v]^f[u-1])==0)printf("Yes\n");
else printf("No\n");
}
}