zoukankan      html  css  js  c++  java
  • [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
    ",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;
    }
    
  • 相关阅读:
    BEGIN2 序列求和
    BEGIN2 序列求和
    《算法竞赛入门经典》 习题45 IP网络(IP Networks,ACM、ICPC NEERC 2005,UVa1590)
    C#中char空值的几种表示方式
    C#中char空值的几种表示方式
    C#中() =>是什么意思
    C#中() =>是什么意思
    C# Task 暂停与取消
    C# Task 暂停与取消
    C# WinForm设置透明
  • 原文地址:https://www.cnblogs.com/ErkkiErkko/p/10291358.html
Copyright © 2011-2022 走看看