zoukankan      html  css  js  c++  java
  • CF1468L

    CF1468L - Prime Divisors Selection

    题目大意

    对于一个序列(A),一个合法的质因子序列(P)满足(forall P_i|A_i,P_i is a prime)

    给定一个序列(a_i,iin[1,n]),求选出(k)个数,使得对于选出的序列(A)

    不存在一个(P)使得(P)中某个元素恰好出现一次

    (nleq 1000,a_ileq 10^{18})


    分析

    由题目的意思我们知道肯定要分解质因数

    Pollard's_Rho!!!

    (10^{18})分解质因数可不是开玩笑的。。。

    所以先考虑合法(A)的判定

    判定(A)合法

    假设可以存在一个元素恰好出现一次(x),那么在(A)所有元素质因子中至少要包含一个(x)

    并且,不存在两个元素只包含(x)

    也就是说,对于合法的(A)中出现的所有质因子(x),都必须存在两个元素只包含(x)

    我们称只包含(x)作为质因子的元素为(x)-元素,为了构造合法的(A),我们必须对于一些(x)选出若干对(x)-元素

    对于每个(x),我们只把前两个(x-)元素视为有效,假设有(c)对这样的元素

    那么情况分几种

    1.(2|k,2cge k),那么直接随意选完即合法

    2.(2cge k,2 ot |k),此时我们需要选出部分对,使得剩下的元素中存在一个数它的因子集已经被选

    枚举剩下一个元素,判定合法即可

    3.(2cleq k),此时可以将(c)对全部选出,判断是否还存在(k-2c)个可以选择即可


    质因数分解

    亲身试验,我的Pollards_Rho它T飞了

    容易发现,对于(x-)元素我们只需要找到它的(a_i=x^k)

    对于其他元素我们只需要找到(a_i)对应的(x)的集合,或者判断无法被(x-)元素集合包含

    由于(nleq 1000),我们可以先得到(x-)元素集合,其他元素我们最后一个个判定

    找到(a_i=x^k)问题简化了很多

    如果你相信std::pow,可以直接来

    只需要找到一个最小的(k'),使得(a_i=x'^{k'}),判定(x')是否为质数,如果是则停止,否则继续分解(x')

    对于(k'leq 3),甚至更大一些的情况,std::pow比较可信

    (k'>3)的情况(实际上(k'=4)(k'=2)包含,所以是(k'ge 5)

    实际上(x')已经很小了,直接枚举质数即可

    素数判定依然需要( ext{Miller_Rabin})但是至少不用Pollards_Rho了

    CodeForces Submission

    const int N=1e5+10;
    
    int n,m;
    int pri[N],pc,notpri[N];
    
    ll qmul(ll x,ll y,ll P){
    	ull z=(long double)x/P*y+0.5;
    	ll res=(ull)x*y-z*P;  Mod2(res);
    	return res;
    }
    ll qpow(ll x,ll k,ll P){
    	ll res=1;
    	for(;k;k>>=1,x=qmul(x,x,P)) if(k&1) res=qmul(res,x,P);
    	return res;
    }
    
    int Miller_Rabin(ll n){
    	if(n<N) return !notpri[n];
    	if(~n&1) return 0;
    	ll s=n-1,t=0;
    	while(s%2==0) s/=2,t++;
    	rep(k,1,7) {
    		ll a=qpow(pri[rand()%pc+1],s,n),b;
    		rep(i,1,t) {
    			b=qmul(a,a,n);
    			if(b==1 && a!=1 && a!=n-1) return 0;
    			a=b;
    		}
    		if(a!=1) return 0;
    	}
    	return 1;
    }
    
    ll a[N],mk[N];
    vector <ll> F[N]; // Factor Set of each element
    vector <ll> IF; // Independent Factor Set
    void unique(vector <ll> &a){ sort(a.begin(),a.end()),a.erase(unique(a.begin(),a.end()),a.end()); }
    
    map <ll,vector<int> > M;
    ll ans[N];
    void Outp(){
    	rep(i,1,m) ans[i]=a[ans[i]];
    	sort(ans+1,ans+m+1);
    	rep(i,1,m) printf("%lld ",ans[i]);
    	exit(0);
    }
    
    ll Root2(ll n){
    	ll x=round(sqrt(n));
    	return x*x==n?x:-1;
    }
    ll Root3(ll n){
    	ll x=round(pow(n,1./3));
    	return x*x*x==n?x:-1;
    }
    
    ll KDivide(ll x){
    	if(Miller_Rabin(x)) return x;
    	ll y;
    	if(~(y=Root2(x))) return KDivide(y);
    	if(~(y=Root3(x))) return KDivide(y);
    	ll U=pow(x,1./5)+4;
    	vector <ll> fac;
    	for(int i=1;pri[i]<=U;++i) if(x%pri[i]==0) {
    		while(x%pri[i]==0) x/=pri[i];
    		fac.pb(pri[i]);
    	}
    	if(fac.size()==1 && x==1) return fac[0];
    	return -1;
    }
    
    
    int main(){
    	rep(i,2,N-1) if(!notpri[i]) {
    		pri[++pc]=i;
    		for(int j=i+i;j<N;j+=i) notpri[j]=1;
    	}
    	n=rd(),m=rd();
    	rep(i,1,n) {
    		ll x=KDivide(a[i]=rd<ll>());
    		if(~x) IF.pb(x);
    	}
    	unique(IF);
    	rep(i,1,n) {
    		ll x=a[i];
    		for(ll y:IF) if(x%y==0) {
    			while(x%y==0) x/=y;
    			F[i].pb(y);
    		}
    		if(x>1) F[i].pb(-1),F[i].pb(-2); // invalid factor, emm... to avoid some situation we push two 
    		if(F[i].size()==1 && M[F[i][0]].size()<2) M[F[i][0]].pb(i),mk[i]=1;
    	}
    	int c=0;
    	for(auto i:M) if(i.second.size()>=2) c++;
    	if(m%2==0 && c*2>=m) {
            // choose k/2 pairs!!
    		int k=m;
    		for(auto i:M) if(i.second.size()>=2) {
    			if(!k) break;
    			rep(j,0,1) ans[k--]=i.second[j];
    		}
    		Outp();
    	}
    	if(c*2>=m) {
            // find another
    		rep(i,1,n) if(!mk[i] && (int)F[i].size()<=m/2) {
    			int f=1;
    			for(ll x:F[i]) if(M[x].size()<2) f=0;
    			if(f) {
    				int k=m;
    				ans[k--]=i;
    				for(ll x:F[i]) {
    					rep(j,0,1) ans[k--]=M[x][j];
    					M.erase(x);
    				}
    				for(auto i:M) if(i.second.size()>=2) {
    					if(!k) break;
    					rep(j,0,1) ans[k--]=i.second[j];
    				}
    				Outp();
    			}
    		}
    	} else {
    		int k=m;
    		for(auto i:M) if(i.second.size()>=2) {
    			if(!k) break;
    			rep(j,0,1) ans[k--]=i.second[j];
    		}
            // Count if we have left much enough...
    		rep(i,1,n) if(!mk[i]) {
    			if(!k) break;
    			int f=1;
    			for(ll x:F[i]) if(M[x].size()<2) f=0;
    			if(f) ans[k--]=i;
    		}
    		if(!k) Outp();
    	}
    	puts("0");
    }
    
  • 相关阅读:
    [笔记] 基于nvidia/cuda的深度学习基础镜像构建流程
    [笔记] Ubuntu 18.04源码编译安装OpenCV 4.0流程
    [笔记] Ubuntu 18.04安装Docker CE及nvidia-docker2流程
    [笔记] Ubuntu 18.04安装cuda 10及cudnn 7流程
    [笔记]Win10下编译Tesseract-OCR 4.0
    [笔记]Python中模块互相调用的例子
    [笔记]mosh使用笔记
    [笔记]Delphi 2007写DLL供VC调用实例
    [笔记]Python的调试器pudb简易教程
    [笔记] Ubuntu下编译ffmpeg+openh264+x264
  • 原文地址:https://www.cnblogs.com/chasedeath/p/14748990.html
Copyright © 2011-2022 走看看