Problem:
Multiplication of Big Integers II

Given two integers $A$ and $B$, compute the product, $A \times B$.

Input

Two integers $A$ and $B$ separated by a space character are given in a line.

Output

Print the product in a line.

Constraints

$-1 \times 10^{200000} \leq A, B \leq 10^{200000}$

Sample Input 1

5 8

Sample Output 1

40

Sample Input 2

100 25

Sample Output 2

2500

Sample Input 3

-1 0

Sample Output 3

0

Sample Input 4

12 -3

Sample Output 4

-36

Solution in C++14 (judge verdict: Accepted)

#pragma region Macro
#pragma region Basic
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef vector<vi> vvi;
typedef vector<vl> vvl;
#define REP(i, n) for (int i = 0, i##_len = (n); i < i##_len; ++i)
#define FOR(i, a, b) for (int i = (a), i##_len = (b); i < i##_len; i++)
#define FORD(i, a, b) for (int i = (a), i##_len = (b); i > i##_len; i--)
#define FORR(t, a) for (auto t : a)
#define ALL(x) (x).begin(), (x).end()  // sortなどの引数を省略したい
#define GET(i, j) get<j>(i)
#define MT(x, ...) make_tuple(x, __VA_ARGS__)
#define SZ(x) ((int)(x).size())
#define ZERO(x) memset(x, 0, sizeof(x))
#define FILL(x, y) memset(x, y, sizeof(x))
#define PB push_back
#define EB emplace_back
#ifdef _DEBUG
#define PRE_COMMAND             \
    std::cin.rdbuf(in.rdbuf()); \
    cout << fixed << setprecision(15);
#else
#define PRE_COMMAND cout << fixed << setprecision(15);
#endif
const double EPS = 1e-10;
const double PI = acos(-1.0);
template <class T>
auto MAX(T& seq) {
    return *max_element(seq.begin(), seq.end());
}
template <class T>
auto MIN(T& seq) {
    return *min_element(seq.begin(), seq.end());
}
template <class T>
auto SUM(T& seq) {
    T temp{0};
    auto& temp2 = temp[0];
    return accumulate(seq.begin(), seq.end(), temp2);
}
template <class T>
void SORT(T& seq) {
    sort(seq.begin(), seq.end());
}
template <class T, class S>
void SORT(T& seq, S& sort_order) {
    sort(seq.begin(), seq.end(), sort_order);
}
template <class T>
void SORTR(vector<T>& seq) {
    sort(seq.begin(), seq.end(), greater<T>());
}
template <class T>
void CHMAX(T& a, const T& b) {
    if (a < b) { a = b; }
}
template <class T>
void CHMIN(T& a, const T& b) {
    if (b < a) { a = b; }
}
template <class T>
set<T> VECTOR_2_SET(vector<T>& v) {
    set<T> s;
    for (auto ele : v) { s.insert(ele); }
    return s;
}
template <class T>
vector<T> SET_2_VECTOR(set<T>& s) {
    vector<T> v;
    for (auto ele : s) { v.push_back(ele); }
    return v;
}
#pragma endregion Basic
#pragma region overload
template <class T, class S>
void operator+=(vector<T>& l, S& r) {
    for (auto i : r) { l.push_back(i); }
}
template <class T, class S>
void operator+=(set<T>& l, S& r) {
    for (auto i : r) { l.insert(i); }
}
template <class T, class S>
void operator+=(multiset<T>& l, S& r) {
    for (auto i : r) { l.insert(i); }
}
template <class T, class S>
vector<T> operator+(vector<T>& l, S& r) {
    vector<T> l_copy = l;
    for (auto i : r) { l_copy.push_back(i); }
    return l_copy;
}
template <class T>
vector<T> operator+(const vector<T> l, const vector<T>& r) {
    vector<T> l_copy = l;
    for (auto i : r) { l_copy.push_back(i); }
    return l_copy;
}
template <class T, class S>
set<T> operator+(set<T>& l, S& r) {
    set<T> l_copy = l;
    for (auto i : r) { l_copy.insert(i); }
    return l_copy;
}
template <class T>
set<T> operator+(const set<T> l, const set<T>& r) {
    set<T> l_copy = l;
    for (auto i : r) { l_copy.insert(i); }
    return l_copy;
}
template <class T, class S>
multiset<T> operator+(multiset<T>& l, S& r) {
    set<T> l_copy = l;
    for (auto i : r) { l_copy.insert(i); }
    return l_copy;
}
template <class T>
multiset<T> operator+(const multiset<T> l, const set<T>& r) {
    set<T> l_copy = l;
    for (auto i : r) { l_copy.insert(i); }
    return l_copy;
}
string operator+(const string l, const string& r) {
    string str = l;
    str += r;
    return str;
}
string operator*(const string l, const size_t& r) {
    string str = l;
    for (size_t i = 0; i < r; i++) { str += l; }
    return str;
}
#pragma endregion overload
#pragma region Input
template <class Head>
void INPUT(vector<Head>& head);
template <size_t N, class Head>
void INPUT(array<Head, N>& head);
template <class T1>
void INPUT(tuple<T1>& t);
template <class T1, class T2>
void INPUT(tuple<T1, T2>& t);
template <class T1, class T2, class T3>
void INPUT(tuple<T1, T2, T3>& t);
template <class T1, class T2, class T3, class T4>
void INPUT(tuple<T1, T2, T3, T4>& t);
template <class T1, class T2, class T3, class T4, class T5>
void INPUT(tuple<T1, T2, T3, T4, T5>& t);
template <class Head>
void INPUT(Head& head);
template <class Head, class... Tail>
void INPUT(Head& head, Tail&... tail);
//本体
template <class Head>
void INPUT(vector<Head>& head) {
    for (size_t i = 0; i < head.size(); i++) { INPUT(head[i]); }
}
template <size_t N, class Head>
void INPUT(array<Head, N>& head) {
    for (size_t i = 0; i < head.size(); i++) { INPUT(head[i]); }
}
template <class T1>
void INPUT(tuple<T1>& t) {
    cin >> get<0>(t);
}
template <class T1, class T2>
void INPUT(tuple<T1, T2>& t) {
    cin >> get<0>(t) >> get<1>(t);
}
template <class T1, class T2, class T3>
void INPUT(tuple<T1, T2, T3>& t) {
    cin >> get<0>(t) >> get<1>(t) >> get<2>(t);
}
template <class T1, class T2, class T3, class T4>
void INPUT(tuple<T1, T2, T3, T4>& t) {
    cin >> get<0>(t) >> get<1>(t) >> get<2>(t) >> get<3>(t);
}
template <class T1, class T2, class T3, class T4, class T5>
void INPUT(tuple<T1, T2, T3, T4, T5>& t) {
    cin >> get<0>(t) >> get<1>(t) >> get<2>(t) >> get<3>(t) >> get<4>(t);
}
template <class Head>
void INPUT(Head& head) {
    cin >> head;
}
template <class Head, class... Tail>
void INPUT(Head& head, Tail&... tail) {
    INPUT(head);
    INPUT((tail)...);
}
#pragma endregion Input
#pragma region Print
template <class T1>
void PRINT2(tuple<T1> t);
template <class T1, class T2>
void PRINT2(tuple<T1, T2> t);
template <class T1, class T2, class T3>
void PRINT2(tuple<T1, T2, T3> t);
template <class T1, class T2, class T3, class T4>
void PRINT2(tuple<T1, T2, T3, T4> t);
template <class T1, class T2, class T3, class T4, class T5>
void PRINT2(tuple<T1, T2, T3, T4, T5> t);
template <class Head>
void PRINT2(vector<Head> head);
template <class Head>
void PRINT2(vector<vector<Head>> head);
template <size_t N, class Head>
void PRINT2(vector<array<Head, N>> head);
template <class... Head>
void PRINT2(vector<tuple<Head...>> head);
template <size_t N, class Head>
void PRINT2(array<Head, N> head);
template <class Head>
void PRINT2(Head head);
template <class Head, class... Tail>
void PRINT2(Head head, Tail... tail);
template <class Head>
void PRINT(Head head);
template <class... Head>
void PRINT(Head... head);
template <int N, class Head>
void PRINT(Head head);
template <class T1>
void PRINT2(tuple<T1> t) {
    PRINT2(get<0>(t));
}
template <class T1, class T2>
void PRINT2(tuple<T1, T2> t) {
    PRINT2(get<0>(t), get<1>(t));
}
template <class T1, class T2, class T3>
void PRINT2(tuple<T1, T2, T3> t) {
    PRINT2(get<0>(t), get<1>(t), get<2>(t));
}
template <class T1, class T2, class T3, class T4>
void PRINT2(tuple<T1, T2, T3, T4> t) {
    PRINT2(get<0>(t), get<1>(t), get<2>(t), get<3>(t));
}
template <class T1, class T2, class T3, class T4, class T5>
void PRINT2(tuple<T1, T2, T3, T4, T5> t) {
    PRINT2(get<0>(t), get<1>(t), get<2>(t), get<3>(t), get<4>(t));
}
template <class Head>
void PRINT2(vector<Head> head) {
    for (auto i = head.begin(); i != head.end(); i++) {
        PRINT2(*i);
        if (i != head.end() - 1) { cout << " "; }
    }
}
template <class Head>
void PRINT2(vector<vector<Head>> head) {
    for (auto i = head.begin(); i != head.end(); i++) {
        PRINT2(*i);
        if (i != head.end() - 1) { cout << endl; }
    }
}
template <size_t N, class Head>
void PRINT2(vector<array<Head, N>> head) {
    for (auto i = head.begin(); i != head.end(); i++) {
        PRINT2(*i);
        if (i != head.end() - 1) { cout << endl; }
    }
}
template <class... Head>
void PRINT2(vector<tuple<Head...>> head) {
    for (auto i = head.begin(); i != head.end(); i++) {
        PRINT2(*i);
        if (i != head.end() - 1) { cout << endl; }
    }
}
template <size_t N, class Head>
void PRINT2(array<Head, N> head) {
    for (auto i = head.begin(); i != head.end(); i++) {
        PRINT2(*i);
        if (i != head.end() - 1) { cout << " "; }
    }
}
template <class Head>
void PRINT2(Head head) {
    cout << head;
}
template <class Head, class... Tail>
void PRINT2(Head head, Tail... tail) {
    PRINT2(head);
    cout << " ";
    PRINT2((tail)...);
}
template <class Head>
void PRINT(Head head) {
    PRINT2(head);
    cout << endl;
}
template <class... Head>
void PRINT(Head... head) {
    PRINT2((head)...);
    cout << endl;
}
template <int N, class Head>
void PRINT(Head head) {
    PRINT2(head);
    cout << endl;
}
#pragma endregion Print
#pragma endregion Macro

struct fft {
    using cd = complex<double>;
    using vcd = vector<complex<double>>;
    array<vcd, 2> exp_list;
    vector<int> result;
    int s;

    fft(vector<int>& x_pre, vector<int>& y_pre) {
        exp_list = {(vcd)(1), (vcd)(1)};
        int x_size = (int)x_pre.size(), y_size = (int)y_pre.size();
        s = x_size + y_size - 1;
        vcd x(s, 0), y(s, 0);
        for (int i = 0; i < x_size; i++) { x[i] = (cd)x_pre[i]; }
        for (int i = 0; i < y_size; i++) { y[i] = (cd)y_pre[i]; }
        result = convolve(x, y);
    }

    // 高速フーリエ変換を行う、inv=trueで逆変換
    void fft_calc(vcd& x, bool inv = false) {
        int h = 1, n = 2, x_size = (int)x.size();
        for (; n < x_size; n *= 2, h++) {}
        x.resize(n, 0);
        cd now = 1, ni = (cd)n;

        // 処理前の並び替え
        for (int i = 0; i < n; i++) {
            int j = 0;
            for (int k = 0; k < h; k++) { j |= ((i >> k) & 1) << (h - 1 - k); }
            if (i < j) { swap(x[i], x[j]); }
        }
        if (exp_list[inv].back() != ni) {
            cd e = exp((cd)(2 * inv - 1) * 1i * PI / ni);
            exp_list[inv].assign(n + 1, 0);
            for (int i = 0; i < n; i++, now *= e) { exp_list[inv][i] = now; }
            exp_list[inv][n] = ni;
        }
        // 各ステップについて処理
        for (int b = 1; b < n; b *= 2) {
            // 各ブロックのj個目
            int m = n / b;
            cd w, u, t;
            for (int j = 0; j < b; j++) {
                w = exp_list[inv][j * m];
                // kを先頭とするブロックに対する処理
                for (int k = 0; k < n; k += 2 * b) {
                    u = x[j + k];
                    t = x[j + k + b] * w;
                    x[j + k] = u + t;
                    x[j + k + b] = u - t;
                }
            }
        }
        if (inv) {
            for (int i = 0; i < x_size; i++) { x[i] /= ni; }
        }
    }

    // aとbの畳み込みを計算
    vector<int> convolve(vcd& x, vcd& y) {
        fft_calc(x);
        fft_calc(y);
        int n = (int)x.size();
        for (int i = 0; i < n; i++) { x[i] *= y[i]; }
        fft_calc(x, true);
        result.assign(s, 0);
        for (int i = 0; i < s; i++) { result[i] = int(real(x[i]) + 0.5); }
        return result;
    }
};

struct bigint {
    int len;  //桁数
    vector<int> digit;
    bool minus = false;
    // +演算の定義
    bigint operator+(bigint const& t) const {
        bigint ret;
        ret.len = max(len, t.len);
        ret.digit.assign(ret.len, 0);
        int temp = ret.len;
        if (minus == t.minus) {
            ret.minus = minus;
            for (int i = 0; i < ret.len; i++) {
                if (i >= len) {
                    ret.digit[i] = t.digit[i];
                } else if (i >= t.len) {
                    ret.digit[i] = digit[i];
                } else {
                    ret.digit[i] = digit[i] + t.digit[i];
                }
            }
        } else if (abscomp(t)) {
            ret.minus = t.minus;
            for (int i = 0; i < temp; i++) {
                if (i >= len) {
                    ret.digit[i] = t.digit[i];
                } else {
                    ret.digit[i] = t.digit[i] - digit[i];
                }
            }
        } else {
            ret.minus = minus;
            for (int i = 0; i < temp; i++) {
                if (i >= t.len) {
                    ret.digit[i] = digit[i];
                } else {
                    ret.digit[i] = digit[i] - t.digit[i];
                }
            }
        }
        ret.shaping();
        return ret;
    }
    // -演算の定義
    bigint operator-(bigint const& t) const {
        bigint ret;
        ret.len = max(len, t.len);
        ret.digit.assign(ret.len, 0);
        int temp = ret.len;
        if (minus != t.minus) {
            ret.minus = minus;
            for (int i = 0; i < ret.len; i++) {
                if (i >= len) {
                    ret.digit[i] = t.digit[i];
                } else if (i >= t.len) {
                    ret.digit[i] = digit[i];
                } else {
                    ret.digit[i] = digit[i] + t.digit[i];
                }
            }
        } else if (abscomp(t)) {
            ret.minus = !t.minus;
            for (int i = 0; i < temp; i++) {
                if (i >= len) {
                    ret.digit[i] = t.digit[i];
                } else {
                    ret.digit[i] = t.digit[i] - digit[i];
                }
            }
        } else {
            ret.minus = minus;
            for (int i = 0; i < temp; i++) {
                if (i >= t.len) {
                    ret.digit[i] = digit[i];
                } else {
                    ret.digit[i] = digit[i] - t.digit[i];
                }
            }
        }
        ret.shaping();
        return ret;
    }
    // *演算の定義
    bigint operator*(bigint& t) {
        bigint ret;
        ret.minus = minus ^ t.minus;
        fft f(digit, t.digit);
        ret.digit = f.result;
        ret.len = (int)ret.digit.size();
        ret.shaping();
        return ret;
    }
    // 単項-演算子の定義
    bigint operator-() const {
        bigint ret = *this;
        ret.minus ^= true;
        ret.shaping();
        return ret;
    }
    // <演算の定義
    bool operator<(bigint const& t) const {
        if (minus != t.minus) { return minus; }
        if (len != t.len) { return (len < t.len) ^ minus; }
        for (int i = len - 1; i >= 0; i--) {
            if (digit[i] != t.digit[i]) {
                return (digit[i] < t.digit[i]) ^ minus;
            }
        }
        return false;
    }
    // コンストラクタ
    bigint(string& s) {
        len = (int)s.size();
        if (s[0] == '-') {
            len--;
            minus = true;
        }
        digit.assign(len, 0);
        for (int i = 0; i < len; i++) {
            digit[i] = s[len - i - 1 + minus] - '0';
        }
        shaping();
    }
    bigint() {}
    // 絶対値の比較
    bool abscomp(bigint const& t) const {
        if (len != t.len) { return len < t.len; }
        for (int i = len - 1; i >= 0; i--) {
            if (digit[i] != t.digit[i]) { return digit[i] < t.digit[i]; }
        }
        return false;
    }
    // 出力
    void print() const {
        string str = "";
        if (minus) { str = "-"; }
        for (int i = len - 1; i >= 0; i--) { str += char('0' + digit[i]); }
        if (len == 0) {
            cout << 0 << '\n';
        } else {
            cout << str << '\n';
        }
    }
    // 整形
    void shaping() {
        for (int i = 0; i < len - 1; i++) {
            if (digit[i] > 9 || digit[i] < 0) {
                digit[i + 1] += digit[i] / 10;
                digit[i] %= 10;
                if (digit[i] < 0) {
                    digit[i] += 10;
                    digit[i + 1]--;
                }
            }
        }
        if (digit[len - 1] > 9) {
            digit.push_back(0);
            digit[len] += digit[len - 1] / 10;
            digit[len - 1] %= 10;
            len++;
        }
        for (int i = len - 1; i >= 0; i--) {
            if (digit[i] == 0) {
                len--;
                digit.pop_back();
            } else {
                break;
            }
        }
        if (len == 0) {
            minus = false;
            len = 1;
            digit.push_back(0);
        }
    }
};

int main() {
    PRE_COMMAND
    string s, t;
    INPUT(s, t);
    bigint b(s);
    bigint c(t);
    (b * c).print();
}