[THUSC2017]杜老师:bitset+线性基

算法一(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\n",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\n",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\n",qpow(2,basis.fail));
	}
	return 0;
}

posted on 2019-01-19 12:33  ErkkiErkko  阅读(473)  评论(0编辑  收藏  举报