Educational Codeforces Round 89 (Rated for Div. 2) D. Two Divisors

题意:

每一组给出一个数 m   ( 2 ≤ m ≤ 1 0 7 ) m~(2 \leq m \leq 10^7) m (2m107) ,找到数 m m m 的两个大于 1 1 1 的因数 d 1 d_1 d1 d 2 d_2 d2 ,使得 g c d ( d 1 + d 2 , m ) = 1 gcd(d_1+d_2,m)=1 gcd(d1+d2,m)=1,存在则输出任意一组,否则答案为 − 1 -1 1 ;
一共有 n   ( 1 ≤ n ≤ 5 ⋅ 1 0 5 ) n~(1 \leq n \leq 5 \cdot 10^5) n (1n5105) 组测试数据,时限 2 s 2s 2s ;

分析:

首先最大公约数有两个基本性质

  1. g c d ( a , b ) = g c d ( a ± b , b ) = g c d ( a , b ± a ) ; gcd(a,b)=gcd(a \pm b,b)=gcd(a,b \pm a); gcd(a,b)=gcd(a±b,b)=gcd(a,b±a);
  2. i f ( g c d ( a , b ) = = 1 )   g c d ( a , b c ) = g c d ( a , c ) ; if(gcd(a,b)==1)~gcd(a,bc)=gcd(a,c); if(gcd(a,b)==1) gcd(a,bc)=gcd(a,c);

我们考虑把数分解质因数,则 m = p 1 k 1 ⋅ p 2 k 2 ⋯ p g k g m=p_1^{k_1} \cdot p_2^{k_2} \cdots p_g^{k_g} m=p1k1p2k2pgkg,考虑 d 1 = p 1 k 1   ,   d 2 = p 2 k 2 ⋯ p g k g d_1=p_1^{k_1}~,~d_2=p_2^{k_2} \cdots p_g^{k_g} d1=p1k1 , d2=p2k2pgkg,那么首先可以确定

  1. g c d ( d 1 , d 2 ) = 1 ; gcd(d_1,d_2)=1; gcd(d1,d2)=1;
  2. m = d 1 ⋅ d 2 ; m=d_1 \cdot d_2; m=d1d2;

因为 g c d ( d 1 + d 2 , d 1 ) = g c d ( d 1 + d 2 , d 2 ) = 1 gcd(d_1+d_2,d_1)=gcd(d_1+d_2,d_2)=1 gcd(d1+d2,d1)=gcd(d1+d2,d2)=1
g c d ( d 1 + d 2 , m ) = g c d ( d 1 + d 2 , d 1 ⋅ d 2 ) = g c d ( d 1 + d 2 , d 1 ) = 1 ; gcd(d_1+d_2,m)=gcd(d_1+d_2,d_1 \cdot d_2)=gcd(d_1+d_2,d_1)=1; gcd(d1+d2,m)=gcd(d1+d2,d1d2)=gcd(d1+d2,d1)=1;

那么只要 m m m 至少有两个不同的素因数就一定有解,介于题目的规模,所以得先用欧拉筛 求出每个数的最小素数;

代码:

#include<bits/stdc++.h>
using namespace std;
#define li long long
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define frep(i,a,b) for(int i=a;i>=b;i--)
const int N = 5E5+10;
const int M = 1E7+10;

int pr[M],minpr[M],cnt;
int ANS[N][2]; 

void eular(int n)
{
	rep(i,2,n){
		if(!minpr[i]) pr[++cnt]=i,minpr[i]=i;
		for(int j=1;j<=cnt&&i*pr[j]<=n;j++){
			minpr[i*pr[j]]=pr[j];
			if(i%pr[j]==0)break;
		}
	}
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	
	eular(1e7);
	int n,x,a;
	cin>>n;
	rep(i,1,n){
		cin>>a; x=a;
		int now=1;
		while(x%minpr[a]==0) now*=minpr[a],x/=minpr[a];
		if(now!=1&&x!=1) ANS[i][0]=now,ANS[i][1]=x;  
		else ANS[i][0]=ANS[i][1]=-1;	
	}
	rep(i,1,n)cout<<ANS[i][0]<<" ";
	cout<<endl;
	rep(i,1,n)cout<<ANS[i][1]<<" ";
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值