본문 바로가기

PS/BOJ

[백준] GCD 곱

반응형

문제 : https://www.acmicpc.net/problem/14860

 

문제요약 : GCD(1, 1) × GCD(1, 2) × ... × GCD(1, M) × GCD(2, 1) × GCD(2, 2) × ... × GCD(2, M) × ... × GCD(N, 1) × GCD(N, 2) × ... × GCD(N, M)을 구해라

 

조건 :

1. 1 ≤ N, M ≤ 15,000,000

 

해설 :

i) Naive Solution

각각의 i(1 ≤ i ≤ N), j(1 ≤ j ≤ M)에 대해 GCD(i, j)를 구해 곱하면서 O(NM)으로 구할 수 있겠죠?

-> 15000000^2이므로 너무 느립니다

 

ii) 조금더 빠르게

N=8, M=8이라 합시다. GCD(i,j)들 중에 2의 인수가 얼마 있는지 알아봅시다.

  1 2 3 4 5 6 7 8
1                
2   2   2   2   2
3                
4   2   4   2   4
5                
6   2   2   2   2
7                
8   2   4   2   8

이제 알 것 같나요?

2의 인수는 sum([n/j]*[m/j] for j = 2^0, 2^1, 2^2, ...)개 있습니다.

min(n,m)까지의 소수들을 구하고 각각의 소수 p에 대해 

z = sum([n/j]*[m/j] for j = p^0, p^1, p^2, ...)

를 구하고 해답에 p^z을 곱하면 됩니다. (pow연산은 O(log z)죠?)

 

소스코드 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <stdio.h>
typedef long long ll;
const ll M=1e9+7;
bool v[20000000];
 
ll lpow(ll m, ll t){
    if(t==1return m;
    if(t==0return 1;
    ll x=lpow(m,t/2)%M; x=(x*x)%M;
    return (x*((t%2)?m:1))%M;
}
 
int main(){
    ll n, m, i, j, p, t;
    scanf("%lld%lld",&n,&m);
    for(t=0, j=2; j<=n; j*=2) t+=((n/j)*(m/j));
    p=lpow(2,t)%M;
    for(j=4; j<=n; j+=2) v[j]=true;
    
    for(i=3; i<=n; i+=2){
        if(!v[i]){
            for(t=0, j=i; j<=n; j*=i) t+=((n/j)*(m/j));
            p=(p*lpow(i,t))%M;
            for(j=i*i; j<=n; j+=i*2) v[j]=true;
        }
    }
    printf("%lld",p%M);
}
cs
반응형

'PS > BOJ' 카테고리의 다른 글

2021 ICPC Sinchon Summer Algorithm Camp Contest - 초급  (0) 2021.08.23
[백준] 이모지  (0) 2019.10.14
[백준] 7대 난제 클리어  (1) 2019.09.18
[백준] 플립과 시프트  (0) 2019.07.14
[백준] Xor Sum  (0) 2019.05.23