算法一(50pts)
分析
有一个很显然的暴力做法,对于区间内的每个数开个bitset,然后暴力分解质因数。如果对于一个数,它的一个质因子的指数是奇数,那么就把bitset的对应位设成(1)。答案就是异或方程组解的个数,也就是(2^{fail}),(fail)表示向线性基插入失败的数的个数。
代码
#include <bits/stdc++.h>
#define rin(i,a,b) for(register int i=(a);i<=(b);++i)
#define irin(i,a,b) for(register int i=(a);i>=(b);--i)
#define trav(i,a) for(register int i=head[a];i;i=e[i].nxt)
typedef long long LL;
typedef std::bitset<175> Bitset;
using std::cin;
using std::cout;
using std::endl;
inline int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int MAXN=1005;
const LL MOD=998244353;
int L,R,cnt,prm[MAXN];
bool vis[MAXN];
void pre_process(int n){
rin(i,2,n){
if(!vis[i]) prm[++cnt]=i;
rin(j,1,cnt){
if(i*prm[j]>n) break;
vis[i*prm[j]]=true;
if(i%prm[j]==0) break;
}
}
}
struct linear_basis{
Bitset a[175];int len,fail;
inline void clear(){
rin(i,0,len-1) a[i].reset();len=fail=0;
}
inline void insert(Bitset x){
if(!x.any()){++fail;return;}
irin(i,len-1,0){
if(!x[i]) continue;
if(!a[i].any()){a[i]=x;break;}
else{x^=a[i];if(!x.any()){++fail;return;}}
}
}
}basis;
inline LL qpow(LL x,LL y){
LL ret=1,tt=x%MOD;
while(y){
if(y&1) ret=ret*tt%MOD;
tt=tt*tt%MOD;
y>>=1;
}
return ret;
}
int main(){
pre_process(1000);
int T=read();
while(T--){
L=read(),R=read();basis.clear();
rin(i,L,R){
int x=i;Bitset temp;temp.reset();
rin(j,1,cnt){
if(x==1) break;
if(x%prm[j]) continue;
int r=0;
while(x%prm[j]==0) x/=prm[j],r^=1;
temp[j-1]=r;basis.len=std::max(basis.len,j);
if(x==1) break;
}
basis.insert(temp);
}
printf("%lld
",qpow(2,basis.fail));
}
return 0;
}
算法二(100pts)
分析
一个显然的性质是对于任意正整数(n)最多只有一个大于(sqrt{n})的质因子(只有这个是我自己想到的ToT),所以我们可以在算法一的基础上,把这些(>sqrt{n})的质因子拿出来单独处理。对于每种质因子,取一个就好了,相当于把这个数的bitset强制插入线性基,并且这次插入必定成功,剩下的和这个数异或一下插入线性基。
但这样还是会TLE。有一个很玄学的优化,当(R-L>6000)时,可以认为每个质数都会单独被挂在线性基上而不是和其他质数一起,因此答案就是(2^{R-L+1-cnt})(正确性不明)。
代码
#include <bits/stdc++.h>
#define rin(i,a,b) for(register int i=(a);i<=(b);++i)
#define irin(i,a,b) for(register int i=(a);i>=(b);--i)
#define trav(i,a) for(register int i=head[a];i;i=e[i].nxt)
typedef long long LL;
typedef std::bitset<455> Bitset;
using std::cin;
using std::cout;
using std::endl;
inline int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int MAXN=1e7+5;
const LL MOD=998244353;
int L,R,cnt,len,prm[MAXN],gp[MAXN],c[MAXN];
bool vis[MAXN];
void pre_process(int n){
rin(i,2,n){
if(!vis[i]) prm[++cnt]=i,gp[i]=i;
rin(j,1,cnt){
if(i*prm[j]>n) break;
vis[i*prm[j]]=true;
gp[i*prm[j]]=gp[i];
if(i%prm[j]==0) break;
}
}
}
struct linear_basis{
Bitset a[452];int len,fail,siz;
inline void clear(){
rin(i,0,len-1) a[i].reset();len=fail=siz=0;
}
inline void insert(Bitset x){
if(siz==len||!x.any()){++fail;return;}
irin(i,len-1,0){
if(!x[i]) continue;
if(!a[i].any()){a[i]=x;++siz;break;}
else{x^=a[i];if(!x.any()){++fail;return;}}
}
}
}basis;
inline LL qpow(LL x,LL y){
LL ret=1,tt=x%MOD;
while(y){
if(y&1) ret=ret*tt%MOD;
tt=tt*tt%MOD;
y>>=1;
}
return ret;
}
inline bool cmp(int x,int y){
return gp[x]<gp[y];
}
int main(){
pre_process(1e7);
int T=read();
while(T--){
L=read(),R=read();
if(R-L>6000){
int temp=0;
rin(i,1,cnt) if((L-1)/prm[i]<R/prm[i]) ++temp; else if(prm[i]>R) break;
printf("%lld
",qpow(2,R-L+1-temp));
continue;
}
basis.clear();len=0;
rin(i,L,R) c[++len]=i; std::sort(c+1,c+len+1,cmp);
Bitset nowbasis;nowbasis.reset();
rin(i,1,len){
int x=c[i];Bitset temp;temp.reset();
if(gp[c[i]]<=3200){
rin(j,1,cnt){
if(x==1) break;
if(x%prm[j]) continue;
int r=0;
while(x%prm[j]==0) x/=prm[j],r^=1;
temp[j-1]=r;basis.len=std::max(basis.len,j);
if(x==1) break;
}
basis.insert(temp);
}
else if(i==1||gp[c[i]]!=gp[c[i-1]]){
x/=gp[x];
rin(j,1,cnt){
if(x==1) break;
if(x%prm[j]) continue;
int r=0;
while(x%prm[j]==0) x/=prm[j],r^=1;
temp[j-1]=r;basis.len=std::max(basis.len,j);
if(x==1) break;
}
nowbasis=temp;
}
else{
x/=gp[x];
rin(j,1,cnt){
if(x==1) break;
if(x%prm[j]) continue;
int r=0;
while(x%prm[j]==0) x/=prm[j],r^=1;
temp[j-1]=r;basis.len=std::max(basis.len,j);
if(x==1) break;
}
basis.insert(temp^nowbasis);
}
}
printf("%lld
",qpow(2,basis.fail));
}
return 0;
}