题解 P7451【[THUSCH2017] 杜老师】
P7451 [THUSCH2017] 杜老师解题报告:
更好的阅读体验
题意
给定
分析
首先看到乘积为完全平方数的子集数量完全可以想到线性基(详见CF895C Square Subsets)。
那么我们有一个初步想法:把是否含有某个质数的奇次幂压成一个二进制数(用
想法很好,但时间复杂度为
考虑根号分治,设
枚举
对于
对于
如果设
这里就要用到一个很玄妙的结论:如果区间长度大于
时间复杂度:
时空复杂度分析有点问题,请轻喷。
代码
#include<stdio.h>
#include<bitset>
using namespace std;
const int maxn=10000005,maxm=455,mod=998244353,t=3200;
int T,A,B,cnt,tp;
int sump[maxn],minn[maxn],ord[maxn],p[maxn],a[maxn],L[maxn],tmpord[maxn];
bitset<maxm>tmp;
bitset<maxm>b[maxm],l[maxm],val[t<<1];
void sieve(int n){
p[1]=1,sump[1]=0,minn[1]=1;
for(int i=2;i<=n;i++){
if(p[i]==0)
a[++cnt]=i,ord[i]=cnt,minn[i]=i;
for(int j=1;j<=cnt;j++){
if(i*a[j]>n)
break;
p[i*a[j]]=1,minn[i*a[j]]=minn[i];
if(i%a[j]==0)
break;
}
sump[i]=sump[i-1]+(p[i]^1);
}
}
int ksm(int a,int b){
int res=1;
while(b){
if(b&1)
res=1ll*res*a%mod;
a=1ll*a*a%mod,b>>=1;
}
return res;
}
int insert(bitset<maxm>b){
for(int i=tp;i>=1;i--){
if(b[i]==0)
continue;
if(l[i].any()==false){
l[i]=b;
return 1;
}
b^=l[i];
}
return 0;
}
int main(){
sieve(10000000);
for(tp=1;a[tp]<=t;tp++);
scanf("%d",&T);
while(T--){
scanf("%d%d",&A,&B);
if(B-A+1>2*t){
int res=B-A+1;
for(int i=1;i<=cnt&&a[i]<=B;i++)
if(B/a[i]!=(A-1)/a[i])
res--;
printf("%d\n",ksm(2,res));
continue;
}
int res=0,tmps=0;
for(int i=1;i<=tp;i++)
l[i].reset();
for(int i=A;i<=B;i++){
int k=i,rec=minn[i];
if(rec>t)
k/=rec;
tmp.reset();
while(k>1){
int w=minn[k],cnt=0;
while(k%w==0)
k/=w,cnt^=1;
tmp[ord[w]]=cnt;
}
if(rec>t){
if(tmpord[rec]==0){
tmpord[rec]=++tmps,val[tmps]=tmp;
continue;
}
tmp^=val[tmpord[rec]];
}
res+=(insert(tmp)^1);
}
for(int i=A;i<=B;i++)
tmpord[minn[i]]=0;
printf("%d\n",ksm(2,res));
}
return 0;
}