Processing math: 4%

[BOJ 13714] 약수의 개수

2022. 2. 8. 17:46PS/백준

위 문제에서 구하고자 하는 것은 다음과 같다.

ai=1bj=1ck=1τ(ijk)

필요한 이론을 증명하고 문제를 해결하자.

 

Theorm 1. τ(ij)=x|iy|j[xy]

 

Lemma 1.

n=ki=0paiit  (pi

일 때 다음은 n의 약수 중 p_{i}들의 배수의 개수이다.

\prod_{i=0}^{k} a_{i} \tau(t)

 

i=p^{a}s(p \nmid s),\ j=p^{b}t(p \nmid t)라 가정하자. 

\tau(ij)=(a+b+1)\tau(st)

s, t가 서로소가 아니므로 위 과정을 반복해주자.

\tau(ij)=(a_{0}+b_{0}+1)(a_{i}+b_{i}+1)\tau(s_{1}t_{1})=\prod_{i=0}^{k} (a_{i}+b_{i}+1) \tau(s_{k})\tau(t_{k})

\gcd(s_{k},t_{k})=1이다. 마찬가지 방법으로 \tau(i), \tau(j)를 전개하자.

\tau(i)=\prod_{i=0}^{k} (a_{i}+1)\ \tau(s_{k})

\tau(j)=\prod_{i=0}^{k} (b_{i}+1)\ \tau(t_{k})

\tau(i)\tau(j)=\prod_{i=0}^{k} (a_{i}b_{i}+a_{i}+b_{i}+1)\ \tau(s_{k})\tau(t_{k})

\tau(ij)\tau(i)\tau(j)에서 a_{i}b_{i}라는 항이 빠진 형태이다. 이것은 i, j의 약수를 각각 x, y라 했을 때 x, y를 동시에 나누는 소수 p가 존재하는 x, y 쌍의 개수를 약수의 곱에서 제외시켜야 함을 의미한다. 즉, 다음과 같이 쓸 수 있다.

 

보충 설명(클릭하세요)

a_{i}\tau(s_{k})b_{i}\tau(t_{k})이고 이 항이 사라진 것이므로 Lemma 1에 의해 동시에 p_{i}으로 나누어 떨어지는 약수가 제외됨을 확인할 수 있다. 

 

\sum_{x|i} \sum_{y|j} 1 - \sum_{x|i} \sum_{y|j}[\gcd(x,y)>1]

\sum_{x|i} \sum_{y|j} [\gcd(x,y)=1] = \sum_{x|i} \sum_{y|j} [x \perp y]

 

위 과정은 i, j 2개인 경우를 진행했다. 3개인 경우는 위의 경우에서 i 또는 j를 더 쪼개면 된다.

\tau(ijk)=\sum_{x|i} \sum_{y|j} \sum_{z|k} [x \perp y] [y \perp z] [z \perp x]

 

 가장 처음의 식을 다음과 같이 변형한다.

\sum_{i=1}^{a} \sum_{j=1}^{b} \sum_{k=1}^{c} \sum_{x|i} \sum_{y|j} \sum_{z|k} [x \perp y] [y \perp z] [z \perp x]

순서를 바꾼다.

\sum_{x=1}^{a} \sum_{y=1}^{b} \sum_{z=1}^{c} \left[a/x\right]\left[b/y\right]\left[c/z\right] [x \perp y] [y \perp z] [z \perp x]

\sum_{x=1}^{a} \left[a/x\right] \sum_{y=1}^{b} \left[b/y\right] [x \perp y] \sum_{z=1}^{c} \left[c/z\right] [x \perp z] \sum_{d|y,z} \mu(d)

y=dp, z=dq라 두자.

\sum_{x=1}^{a} \left[a/x\right] \sum_{d=1}^{\min(b,c)} \mu(d) [x \perp d] \sum_{p=1}^{\left[b/d\right]} \left[b/dp\right] [x \perp p] \sum_{q=1}^{\left[c/d\right]} \left[c/dq\right] [x \perp q]

W(s, t)=\sum_{i=1}^{s} \left[s/i\right] [t \perp i]

라 정의한다. 다시 표현하면

\sum_{x=1}^{a} \left[a/x\right] \sum_{d=1}^{\min(b,c)} \mu(d) [x \perp d] W(\left[b/d\right], x) W(\left[c/d\right], x)

[x \perp y]의 누적합을 전처리 한다면 WO(\sqrt{s})안에 계산할 수 있다. \mu(y) [x \perp y]의 누적합을 전처리 한다면 \sum_{d=1}^{\min(b,c)}O(\sqrt{n})으로 계산할 수 있다. 따라서 전체 시간 복잡도는 O(n^{2})이다.

 

이것을 구현한 코드이다.

코드 보기

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include<stdio.h>
typedef long long ll;
#define sz 2001
ll cop[sz][sz];
ll pre_cop[sz][sz];
ll mu_cop[sz][sz];
ll mu[sz];
ll mod=1<<30;
ll sp[sz];
ll prime[sz],pt;
ll pre_bc[sz];
ll min(ll a,ll b){
    return a>b?b:a;
}
ll W(ll s,ll t){
    ll i,j,sum=0;
    for(i=1;i<=s;i=j+1){
        j=s/(s/i);
        sum+=s/i*(pre_cop[t][j]-pre_cop[t][i-1])%mod;
        sum%=mod;
    }
    return sum;
}
int main(){
    ll i,j,k;
    for(i=1;i<sz;i++){
        for(j=1;j<sz;j++) cop[i][j]=1;
    }
    for(i=2;i<sz;i++){
        ll h=i;
        for(j=2;j*j<=h;j++){
            if(h%j==0){
                for(k=j;k<sz;k+=j){
                    cop[i][k]=0;
                }
                while(h%j==0) h/=j;
            }
        }
        if(h-1){
            for(j=h;j<sz;j+=h) cop[i][j]=0;
        }
        for(j=1;j<sz;j++) pre_cop[i][j]=cop[i][j]+pre_cop[i][j-1];
    }
    for(i=1;i<sz;i++){
        pre_cop[1][i]=cop[1][i]+pre_cop[1][i-1];
    }
    mu[1]=1;
    for(i=2;i<sz;i++){
        if(!sp[i]){
            prime[pt++]=i;
            mu[i]=-1;
        }
        for(j=0;j<pt;j++){
            if(i*prime[j]>sz) break;
            sp[i*prime[j]]=1;
            if(i%prime[j]==0break;
            mu[i*prime[j]]=mu[i]*mu[prime[j]];
        }
    }
    for(i=1;i<sz;i++){
        for(j=1;j<sz;j++){
            mu_cop[i][j]=mu[j]*cop[i][j]+mu_cop[i][j-1];
        }
    }
    ll a,b,c,sum=0;
    scanf("%lld %lld %lld",&a,&b,&c);
    for(i=1;i<=min(b,c);i=pre_bc[i]+1){
        pre_bc[i]=min(b/(b/i),c/(c/i));
    }
    for(i=1;i<=a;i++){
        ll s=0;
        for(j=1;j<=min(b,c);j=k+1){
            k=pre_bc[j];
            s+=W(b/j,i)*W(c/j,i)%mod*(mu_cop[i][k]-mu_cop[i][j-1])%mod;
            s%=mod;
        }
        sum=(sum+s*(a/i)%mod)%mod;
    }
    printf("%lld",sum);
}
cs

 

 

'PS > 백준' 카테고리의 다른 글

[BOJ 17105] 골드바흐 트리플  (0) 2022.03.04
[BOJ 16808] Identity Function  (0) 2022.02.14
[BOJ 18496] Euclid's Algorithm  (0) 2022.01.16
64일 스트릭!!  (0) 2021.12.20
[BOJ 10438] 페리 수열의 합  (0) 2021.11.20