abc238g

思路

莫队

哈希。

质因数分解,指数模 。直接乘过大,考虑哈希。每个质数的指数和都因为 的倍数。

即:所有数的出现次数和是否都为 的倍数。

法一:前缀和。给每个质数随机 ,做前缀和。如果是完全立方数可推出 。因为对 取模,所以 可看作从 中随机。显然只做一次是不行的,重复 次。可以大概认为单次正确率为 ,一道题正确率 是测试点数。

法二:异或。给每个质数随机 个值,令 。从前往后,如果当前 有质因数 前已经出现 次, 取模, 异或上 。做前缀异或和,如果是完全立方数可推出 。因为是异或,所以错误率极低。

法一适合 较大,法二适合 较小,代码用法二。

另外,既然不用莫队,可以把复杂度优化到 ,筛质数的时候记录 表示 最小的质因数。

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