A * B 只有 60 分
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <iostream>
using namespace std;
const int K = 10000, WIDTH = 4;
const int N = 2e4 + 5, P = 998244353, G = 3, Gi = 332748118;
int rev[N];
inline void init(int Lim, int L) {
for (int i = 0; i < Lim; i++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (L - 1));
}
inline int qkpow(int a, int b) {
int ans = 1;
while (b) {
if (b & 1)
ans = 1ll * ans * a % P;
a = 1ll * a * a % P;
b >>= 1;
}
return ans;
}
inline void NTT(int *A, int Lim, int on) {
for (int i = 0; i < Lim; i++)
if (i < rev[i])
swap(A[i], A[rev[i]]);
for (int h = 1; h < Lim; h <<= 1) {
int wn = qkpow(on == 1 ? G : Gi, (P - 1) / (h << 1));
for (int j = 0; j < Lim; j += (h << 1)) {
int w = 1;
for (int k = 0; k < h; k++) {
int x = A[j | k], y = 1ll * w * A[j | k | h] % P;
A[j | k] = (x + y) % P;
A[j | k | h] = (x - y + P) % P;
w = 1ll * w * wn % P;
}
}
}
if (on == -1) {
int inv = qkpow(Lim, P - 2);
for (int i = 0; i < Lim; i++) A[i] = 1ll * A[i] * inv % P;
}
}
class Integer {
public:
int size, num[N];
Integer() {
size = 0;
memset(num, 0, sizeof(num));
}
Integer(int data) { //整形赋值
size = 0;
while (data) {
num[size++] = data % K;
data /= K;
}
}
Integer &operator=(Integer);
inline void init(string data) { //字符串赋值
size = 0;
int len = data.length();
int cnt = 1;
for (int i = len - 1; i >= 0; i--) {
if (data[i] >= '0' && data[i] <= '9')
num[size] = num[size] + (data[i] - '0') * cnt, cnt *= 10;
if (cnt >= K)
cnt = 1, size++;
// else
// num[size++] = data[i] - 'A' + 10;
}
if (cnt != 1)
size++;
}
};
ostream &operator<<(ostream &os, Integer A) {
char x = os.fill();
streamsize y = os.width();
for (int i = A.size - 1; i >= 0; i--)
// if (A.num[i] >= 10)
// os << char(A.num[i] - 10 + 'A');
// else
os << A.num[i], os.width(WIDTH), os.fill('0');
os.fill(x);
os.width(y);
return os;
}
Integer operator+(const Integer &A, const Integer &B) {
Integer Ans;
int s = max(A.size, B.size);
Ans.size = s;
int x = 0;
for (int i = 0; i < s; i++) {
Ans.num[i] = A.num[i] + B.num[i] + x;
x = Ans.num[i] / K;
Ans.num[i] = Ans.num[i] % K;
}
if (x)
Ans.num[Ans.size++] = x;
while (Ans.num[Ans.size - 1] == 0 && Ans.size > 1) Ans.size--;
return Ans;
}
Integer operator-(const Integer &A, const Integer &B) { // A >= B
Integer Ans;
int s = max(A.size, B.size);
Ans.size = s;
int x = 0;
for (int i = 0; i < s; i++) {
Ans.num[i] = A.num[i] - B.num[i] - x;
x = (Ans.num[i] < 0 ? 1 : 0);
Ans.num[i] += K * x;
}
while (Ans.num[Ans.size - 1] == 0 && Ans.size > 1) Ans.size--;
return Ans;
}
int ta[N << 1], tb[N];
Integer operator*(Integer A, Integer B) {
Integer Ans;
while (A.num[A.size - 1] == 0 && A.size > 1) A.size--;
while (B.num[B.size - 1] == 0 && B.size > 1) B.size--;
int N = A.size, M = B.size, Lim = 1, L = 0;
for (int i = 0; i < A.size; i++) ta[i] = A.num[i];
for (int i = 0; i < B.size; i++) tb[i] = B.num[i];
while (Lim < N + M) Lim <<= 1, L++;
for (int i = A.size; i <= Lim; i++) ta[i] = 0;
for (int i = B.size; i <= Lim; i++) tb[i] = 0;
init(Lim, L);
NTT(ta, Lim, 1);
NTT(tb, Lim, 1);
for (int i = 0; i < Lim; i++) ta[i] = 1ll * ta[i] * tb[i] % P;
NTT(ta, Lim, -1);
long long x = 0;
for (int i = 0; i < Lim; i++) {
Ans.num[i] = 0;
Ans.num[i] = ta[i] + x;
x = Ans.num[i] / K;
Ans.num[i] %= K;
}
int len = Lim + 1;
Ans.num[Lim] = x;
while (Ans.num[len - 1] == 0 && len > 1) len--;
Ans.size = len;
return Ans;
}
int c[N];
Integer operator/(Integer A, int b) {
Integer Ans;
string s = "";
long long x = 0, cnt = 0;
for (int i = A.size - 1; i >= 0; i--) {
c[i] = 1ll * (A.num[i] + x * K) / b;
x = 1ll * (A.num[i] + x * K) % b;
}
int E = A.size;
while (c[E - 1] == 0 && E > 1) E--;
for (int i = E - 1; i >= 0; i--) {
if (c[i] >= 1000 || i == E - 1)
s += to_string(c[i]);
else if (c[i] >= 100)
s += "0" + to_string(c[i]);
else if (c[i] >= 10)
s += "00" + to_string(c[i]);
else if (c[i] >= 1)
s += "000" + to_string(c[i]);
else
s += "0000";
}
Ans.init(s);
return Ans;
}
bool operator<(const Integer &A, const Integer &B) {
if (A.size < B.size)
return 1;
if (A.size > B.size)
return 0;
for (int i = A.size - 1; i >= 0; i--) {
if (A.num[i] < B.num[i])
return 1;
if (A.num[i] > B.num[i])
return 0;
}
return 0;
}
bool operator>(const Integer &A, const Integer &B) {
if (A.size > B.size)
return 1;
if (A.size < B.size)
return 0;
for (int i = A.size - 1; i >= 0; i--) {
if (A.num[i] > B.num[i])
return 1;
if (A.num[i] < B.num[i])
return 0;
}
return 0;
}
bool operator==(const Integer &A, const Integer &B) {
if (A.size > B.size)
return 0;
if (A.size < B.size)
return 0;
for (int i = A.size - 1; i >= 0; i--) {
if (A.num[i] > B.num[i])
return 0;
if (A.num[i] < B.num[i])
return 0;
}
return 1;
}
Integer &Integer::operator=(Integer B) {
for (int i = B.size; i < size; i++) num[i] = 0;
size = B.size;
for (int i = 0; i < size; i++) num[i] = B.num[i];
for (int i = size; i < N; i++) num[i] = 0;
return *this;
}
bool operator<=(const Integer &A, const Integer &B) {
if (A.size < B.size)
return 1;
if (A.size > B.size)
return 0;
for (int i = A.size - 1; i >= 0; i--) {
if (A.num[i] < B.num[i])
return 1;
if (A.num[i] > B.num[i])
return 0;
}
return 1;
}
bool operator>=(const Integer &A, const Integer &B) {
if (A.size > B.size)
return 1;
if (A.size < B.size)
return 0;
for (int i = A.size - 1; i >= 0; i--) {
if (A.num[i] > B.num[i])
return 1;
if (A.num[i] < B.num[i])
return 0;
}
return 1;
}
Integer qpow(Integer A, int b) {
Integer Ans;
Ans.init("1");
while (b > 0) {
if (b & 1)
Ans = Ans * A;
A = A * A;
b >>= 1;
}
return Ans;
}
Integer nth_ROOT(Integer A, int b) { //高精度开根
Integer L, R, mid;
L.init("0"), R.init("10");
R = qpow(R, (A.size * 4 / b + 1));
while (L + 1 < R) {
mid = (L + R) / 2;
if (qpow(mid, b) <= A)
L = mid;
else
R = mid;
}
if (qpow(L, b) <= A)
return L;
else
return R;
}
string a, b;
Integer A, B;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> a >> b;
A.init(a), B.init(b);
cout << A * B << endl;
return 0;
}