코딩스토리

백준 15576 - 큰 수 곱셈 (2) 본문

알고리즘/BOJ 문제 풀이

백준 15576 - 큰 수 곱셈 (2)

kimtaehyun98 2020. 11. 24. 12:02

www.acmicpc.net/problem/15576

 

15576번: 큰 수 곱셈 (2)

C++17, C11, C99, C++98, C++11, C++14, C99 (Clang), C++98 (Clang), C++11 (Clang), C++14 (Clang), C11 (Clang), C++17 (Clang)

www.acmicpc.net

 

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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#include <iostream>
#include <complex>
#include <vector>
#include <cstring>
#include <string>
#include <algorithm>
 
// Koosaga 팀노트 FFT 코드
using namespace std;
typedef complex<double> base;
typedef long long ll;
const double PI = acos(-1);
 
void fft(vector<base>& a, bool inv = false) {
    int n = a.size(), j = 0;
    // 분할 정복 기법, 이때 n은 무조건 2^n 승임
    vector<base> roots(n / 2);
    for (int i = 1; i < n; i++) {
        int bit = (n >> 1);
        while (j >= bit) {
            j -= bit;
            bit >>= 1;
        }
        j += bit;
        if (i < j) swap(a[i], a[j]);
    }
    double ang = 2 * acos(-1/ n * (inv ? -1 : 1);
    for (int i = 0; i < n / 2; i++) {
        roots[i] = base(cos(ang * i), sin(ang * i));
    }
    for (int i = 2; i <= n; i <<= 1) {
        int step = n / i;
        for (int j = 0; j < n; j += i) {
            for (int k = 0; k < i / 2; k++) {
                base u = a[j + k], v = a[j + k + i / 2* roots[step * k];
                a[j + k] = u + v;
                a[j + k + i / 2= u - v;
            }
        }
    }
    if (inv) for (int i = 0; i < n; i++) a[i] /= n;
}
 
vector<ll> multiply(vector<ll>& v, vector<ll>& w) {
    vector<base> fv(v.begin(), v.end()), fw(w.begin(), w.end());
    // n이 무조건 2^n 이여야 하기 때문에 변환!
    int n = 2while (n < v.size() + w.size()) n <<= 1;
    fv.resize(n); fw.resize(n);
    fft(fv, 0); fft(fw, 0);
    for (int i = 0; i < n; i++) fv[i] *= fw[i];
    fft(fv, 1);
    vector<ll> ret(n);
    for (int i = 0; i < n; i++) ret[i] = (ll)round(fv[i].real());
    return ret;
}
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    
    string str1, str2;
    cin >> str1 >> str2;
    // 둘 중 하나라도 0이면 예외처리
    if (str1 == "0" || str2 == "0") {
        cout << 0 << "\n";
        return 0;
    }
    vector<ll> a(str1.size()), b(str2.size());
    for (int i = 0; i < str1.size(); i++)a[str1.size() - i - 1= str1[i] - '0';
    for (int i = 0; i < str2.size(); i++)b[str2.size() - i - 1= str2[i] - '0';
    vector<ll> ret = multiply(a, b);
 
    // 배열의 마지막부터 채우면서 ret에 들어있는 값들을 더해줌
    // 이 때 원래 라면 매 진행마다 10을 곱해줘야 하는데 그러면 오버플러우 날 것 같아서
    // 10을 곱해주는 대신 자리수를 하나 올려줌으로써 해결(ten 변수가 자리수 한자리씩 올려주는 변수)
    /*ex)123 * 456 이라면
          18       <- ret[0]
         27        <- ret[1]
        28         <- ret[2]
       13          <- ret[3]
       4           <- ret[4]
    =  56088 
    */
 
    for (int i = 0; i < str1.size() + str2.size() - 1; i++) {
        ret[i + 1+= ret[i] / 10;
        ret[i] = ret[i] % 10;
    }
    int cnt = ret.size() - 1;
    while (ret[cnt] == 0) {
        cnt--;
        if (cnt == 0break;
    }
    for (int i = cnt; i >= 0; i--cout << ret[i];
    cout << "\n";
}
cs

 

Comments