Educational Codeforces Round 89 (Rated for Div. 2) D. Two Divisors (唯一分解定理&素数)

题目传送门: Codeforces

题目大意:

给n个数,a[ i ] ~ a[ n ],找到a的两个除数,d1(d1>1) 和 d2 (d2>1), 而且这两个除数满足gcd(d1+d2, a)=1,输出这n个数满足条件的d1和d2(如果答案有多个,随机输出), 如果不存在,d1=-1, d2=-1。

思路:

看到找除数,我们很容易想到唯一分解定理:
m = p 1 a 1 p 2 a 2 p 3 a 3 . . . . . . p n a n , ( p 1 , p 2.... p n 均 为 素 数 ) m = p1^{a1}p2^{a2}p3^{a3}......pn^{an}, (p1,p2.... pn 均为素数) m=p1a1p2a2p3a3......pnan,(p1,p2....pn)
对于最大公约数有两个基本性质:
1.   g c d ( a , b ) = g c d ( a ± b , b ) = g c d ( a , b ± a ) ; 1.\ gcd(a,b)=gcd(a±b,b)=gcd(a,b±a); 1. 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 ) ; 2.\ if(gcd(a,b)==1), gcd(a,bc)=gcd(a,c); 2. if(gcd(a,b)==1),gcd(a,bc)=gcd(a,c);
将一个数分解为质因数后,进行如下操作:
d 1 = p 1 a 1 , d 2 = p 2 a 2 p 3 a 3 . . . . . . p n a n ; d1=p1^{a1}, d2=p2^{a2}p3^{a3}......pn^{an}; d1=p1a1,d2=p2a2p3a3......pnan; m = d 1 ∗ d 2 , g c d ( d 1 , d 2 ) = 1 ; m=d1*d2, \quad gcd(d1,d2)=1; m=d1d2,gcd(d1,d2)=1; g c d ( d 1 , d 2 ) = g c d ( d 1 + d 2 , d 2 ) = g c d ( d 1 , d 1 + d 2 ) = 1 gcd(d1,d2)=gcd(d1+d2,d2)=gcd(d1,d1+d2)=1 gcd(d1,d2)=gcd(d1+d2,d2)=gcd(d1,d1+d2)=1则: g c d ( d 1 + d 2 , d 1 ∗ d 2 ) = g c d ( d 1 + d 2 , m ) = g c d ( d 1 , d 1 ) = 1 gcd(d1+d2,d1*d2)=gcd(d1+d2,m)=gcd(d1,d1)=1 gcd(d1+d2,d1d2)=gcd(d1+d2,m)=gcd(d1,d1)=1
对于此题,我们先求出0~100000之间所有素数,然后对于每一个a[i], 利用唯一分解定理求解,如果a[i]是素数,直接d1=d2=-1, 确保d1>1,d2>1。

代码如下:
#include 
 
using namespace std;
#define ll long long
const int Max=1e6+7;
int d1[Max], d2[Max], a[Max];
int prime[100006];
bool isPrime(int n){
    if(n==2 ||n==3) return true;
    if(n%6!=1 && n%6!=5) return false;
    int nsqrt=sqrt(n);
    for(int i=5; i<=nsqrt; i+=6){
        if(n%i==0 || n%(i+2)==0 ) return false;
    }
    return true;
}
// 筛选素数
void getprime(){
    int index=0;
    for(int i=2; i<=100000; i++){
        if( isPrime(i) ) prime[++index]=i;
    }
}
 
int main(){
    ios::sync_with_stdio(0);
    getprime();
    int n; scanf("%d",&n);
    memset(d1,0,sizeof d1); memset(d2,0,sizeof d2);
    for(int i=1; i<=n; i++) scanf("%d",&a[i]);
    for(int i=1; i<=n; i++){
        if(isPrime(a[i])){
            d1[i]=d2[i]=-1; continue;
        }
        int index=1;
        int t=a[i];
        while(t>1){ 
            if(t%prime[index]==0){ // 找出 p1^a1
                int c=prime[index];
                t=t/prime[index];
                while(t%prime[index]==0){
                    c*=prime[index];
                    t/=prime[index];
                    if(t<=1) break;
                }
                d1[i]=c; d2[i]=a[i]/c;
                break;
            }
            index++;
        }
        if(d1[i]<=1 || d2[i]<=1) d1[i]=d2[i]=-1;
    }

           for(int i=1; i<=n; i++){
                if(i==1) printf("%d",d1[i]);
                else printf(" %d",d1[i]);
           } printf("\n");
            for(int i=1; i<=n; i++){
                if(i==1) printf("%d",d2[i]); 
                else printf(" %d",d2[i]); 
           } printf("\n");
    return 0;
}

你可能感兴趣的:(Codeforces)