题提供二进制分解进位的思路。
得到多项式系数后,考虑对多项式进位。显然
时不需要进位,考虑其他的
的情况。一种比较直观的想法是,对
进行二进制分解,二进制分解可以得到
,显然
,有
。对于项
,有
。那么
,实现进位。进位完成后考虑
的变化,显然
最后的系数与二进制第
位有关。
需要注意的是,的正负性对
带来的影响,毕竟负数多了一个
,所以是
。
特别的,对于是负数时,进位完成后可能变成
,这显然不是我们想要的,其实很好解决,因为
,所以此时需要再进一次位
最重要的是,由于不断进位,所以不能保证已经得到的系数数组是足够大的,特别是对
来说,需要用
扩容,保证数组不越界(因为这个导致
了三小时还没发现问题,最后只能下班)。
对比官解,虽然提到解法很典,但是由于之前确实没接触过这种进位,所以看不懂题解,这种做法虽然麻烦,复杂度多了一些二进制枚举的常数,但是更容易推导与接受。两种做法最后的答案都一样,所以我想,这种做法与官解,本质上是相同的吧。
至于为什么要多项式算系数,我想当你发现读了半天题目还不知道怎么用原式推关于的多项式,但是用多项式却很好推进制表示,多项式相乘又能得到正确的相乘结果的时候,多项式乘法就呼之欲出了吧。
#include <bits/stdc++.h>
#define int long long
#include <complex>
const double PI = acos(-1.0);
void FFT(std::vector<std::complex<double>> &a, int ops) {
int n = a.size();
std::vector<int> rev(n);
for (int i = 0; i < n; ++i) {
rev[i] = (rev[i >> 1] >> 1);
if (i & 1) {
rev[i] |= (n >> 1);
}
}
for (int i = 0; i < n; ++i) {
if (i < rev[i]) {
std::swap(a[i], a[rev[i]]);
}
}
for (int i = 2; i <= n; i <<= 1) {
int mid = i >> 1;
std::complex<double> wn(cos(2 * PI * ops / i), sin(2 * PI * ops / i));
for (int j = 0; j < n; j += i) {
std::complex<double> w(1, 0);
for (int k = 0; k < mid; ++k) {
std::complex<double> x = a[j + k];
std::complex<double> y = w * a[j + k + mid];
a[j + k] = x + y;
a[j + k + mid] = x - y;
w *= wn;
}
}
}
if (ops == -1) {
for (int i = 0; i < n; ++i) {
a[i] /= n;
}
}
}
std::vector<int> mul(std::vector<int> &a, std::vector<int> &b) {
int n = a.size(), m = b.size();
int len = 1;
while (len < n + m) {
len <<= 1;
}
std::vector<std::complex<double>> A(len), B(len);
for (int i = 0; i < n; i++) {
A[i] = std::complex<double>(a[i], 0);
}
for (int i = 0; i < m; i++) {
B[i] = std::complex<double>(b[i], 0);
}
FFT(A, 1);
FFT(B, 1);
std::vector<std::complex<double>> C(len);
for (int i = 0; i < len; i++) {
C[i] = A[i] * B[i];
}
FFT(C, -1);
std::vector<int> c(n + m - 1);
for (int i = 0; i < n + m - 1; i++) {
c[i] = static_cast<int>(C[i].real() + 0.5);
if (c[i] < 0) {
c[i] = 0;
}
}
return c;
}
void solve() {
std::string s1, s2;
std::cin >> s1 >> s2;
int n = s1.size(), m = s2.size();
std::vector<int> a(n), b(m);
for (int i = 0; i < n; i++) {
a[i] = (s1[n - i - 1] == '0' ? 0 : 1);
}
for (int i = 0; i < m; i++) {
b[i] = (s2[m - i - 1] == '0' ? 0 : 1);
}
std::vector<int> c = mul(a, b);
int len = c.size();
auto work = [&](int i, int ops) -> void {
int k, tmp = abs(c[i]);
for (int j = 1; j <= 63; j++) {
k = (tmp >> j) & 1;
if (!k) {
continue;
}
if (2 * j + i >= len) {
len = 2 * j + i + 1;
c.resize(len);
}
c[2 * j + i]+=ops*pow(-1,j);
}
k = (tmp >> 0) & 1;
if (k) {
c[i] = ops;
} else {
c[i] = 0;
}
};
for (int i = 0; i < len; i++) {
if (c[i] > 1) {
work(i, 1);
} else if (c[i] < 1) {
work(i, -1);
if (c[i] == -1) {
if (i + 2 >= len) {
len = i + 3;
c.resize(len);
}
c[i + 2]++;
c[i] = 1;
}
}
}
while (c.size() > 1 && c.back() == 0) {
c.pop_back();
}
for (int i = c.size() - 1; i >= 0; i--) {
std::cout << c[i];
}
std::cout << '\n';
}
signed main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0), std::cout.tie(0);
int t = 1;
std::cin >> t;
while (t--) {
solve();
}
return 0;
}