Description
以二进制形式给出两个数,求它们的乘积,也以二进制表示。
Input
每组数据两行,每行一个二进制表示的正整数。01串的长度不大于40000
Output
输出二进制表示的两数乘积。
Sample Input
111
100
Sample Output
11100
Hint
当规模足够小时可直接使用非优化算法以减少常数复杂度运算。
参考代码框架
// 整数位乘
struct BigBinary
{
std::vector<int> x; // 由低位到高位保存二进制位
bool neg; // 标记数的正负
void Init(){x.clear(); neg = false;}
BigBinary(){Init();}
void Print()
{
if(neg && !x.empty()) printf("-");
for(int i = x.size() - 1; i >= 0; i --)
printf("%d", x[i]);
if(x.empty()) printf("0");
printf("\n");
}
};
BigBinary Add(BigBinary &a, BigBinary &b)
{
// TODO: 返回 a + b 的结果,小心两数异号情况
}
BigBinary Minus(BigBinary &a, BigBinary &b)
{
// TODO: 返回 a - b 的结果,注意正负号
}
BigBinary Mul(BigBinary &a, BigBinary &b)
{
// TODO: 模拟竖式计算两数相乘
}
void MulN2(BigBinary &a, int n_2)
{
// TODO: 为 a 添加 n_2 个二进制0,即乘以 2^(n_2)
}
BigBinary FasterMul(BigBinary &a, BigBinary &b)
{
// TODO: 分治优化位乘
// 设 a = A * 2^(n/2) + B, b = C * 2^(n/2) + D
// ab = AC2^n + [(A - B)(D - C) + AC + BD] * 2^(n/2) + BD
// 注意:a 和 b 位数不一定相同,需要额外处理边界。
}
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<vector>
struct BigBinary
{
std::vector<int> x;
bool neg;
void Init(){x.clear(); neg = false;}
unsigned size(){return x.size();}
BigBinary(){Init();}
void check0()
{
while(!x.empty() && x.back() == 0) x.pop_back();
if(x.size() == 0) neg = false;
}
void Print()
{
if(neg && !x.empty()) printf("-");
for(int i = x.size() - 1; i >= 0; i --)
printf("%d", x[i]);
if(x.empty()) printf("0");
printf("\n");
}
};
bool AbsAgB(BigBinary &a, BigBinary &b)
{
if(a.size() > b.size()) return true;
if(b.size() > a.size()) return false;
for(int i = a.size() - 1; i >= 0; i --)
{
if(a.x[i] > b.x[i]) return true;
if(b.x[i] > a.x[i]) return false;
}
return true;
}
BigBinary Add(BigBinary &a, BigBinary &b);
BigBinary Minus(BigBinary &a, BigBinary &b);
BigBinary Add(BigBinary &a, BigBinary &b)
{
BigBinary c;
if(a.neg != b.neg)
{
if(AbsAgB(a, b))
{
b.neg ^= 1;
c = Minus(a, b);
b.neg ^= 1;
}
else
{
a.neg ^= 1;
c = Minus(b, a);
a.neg ^= 1;
}
return c;
}
if(a.size() < b.size()) return Add(b, a);
c.x = a.x;
for(int i = 0; i < b.size(); i ++) c.x[i] += b.x[i];
int cur = 0;
for(int i = 0; i < c.size(); i ++)
{
c.x[i] += cur;
cur = c.x[i] >> 1;
c.x[i] &= 1;
}
for(; cur; cur >>= 1) c.x.push_back(cur & 1);
c.neg = a.neg; c.check0();
return c;
}
BigBinary Minus(BigBinary &a, BigBinary &b)
{
BigBinary c;
if(a.neg != b.neg)
{
b.neg ^= 1;
c = Add(a, b);
b.neg ^= 1;
return c;
}
if(!AbsAgB(a, b))
{
a.neg ^= 1;
b.neg ^= 1;
c = Minus(b, a);
a.neg ^= 1;
b.neg ^= 1;
return c;
}
int i;
for(i = 0; i < b.size(); i ++)
c.x.push_back(a.x[i] - b.x[i]);
for(; i < a.size(); i ++)
c.x.push_back(a.x[i]);
for(i = 0; i < c.size(); i ++)
{
while(c.x[i] < 0)
{
c.x[i] += 2;
c.x[i + 1] --;
}
}
c.neg = a.neg; c.check0();
return c;
}
BigBinary Mul(BigBinary &a, BigBinary &b)
{
BigBinary c;
for(int i = 0; i < a.size(); i ++)
{
for(int j = 0; j < b.size(); j ++)
{
while(c.x.size() < i + j + 1)
c.x.push_back(0);
c.x[i + j] += a.x[i] & b.x[j];
}
}
int cur = 0;
for(int i = 0; i < c.size(); i ++)
{
c.x[i] += cur;
cur = c.x[i] >> 1;
c.x[i] &= 1;
}
for(; cur; cur >>= 1) c.x.push_back(cur & 1);
c.neg = a.neg ^ b.neg; c.check0();
return c;
}
void MulN2(BigBinary &a, int n_2)
{
int isize = a.x.size();
a.x.resize(isize + n_2);
for(int i = a.x.size() - 1, j = isize - 1; j >= 0; i --, j--)
a.x[i] = a.x[j];
for(int i = n_2 - 1; i >= 0; i --)
a.x[i] = 0;
}
BigBinary FasterMul(BigBinary &a, BigBinary &b)
{
if(a.size() < 2 || b.size() < 2)
return Mul(a, b);
if(a.size() < 100 && b.size() < 100)
return Mul(a, b);
if(a.size() < b.size())
return FasterMul(b, a);
BigBinary A, B, C, D;
int n_2 = a.size() >> 1;
for(int i = 0; i < n_2; i ++)
B.x.push_back(a.x[i]);
B.check0();
for(int i = n_2; i < a.size(); i ++)
A.x.push_back(a.x[i]);
A.check0();
BigBinary ret;
if(b.size() < n_2)
{
BigBinary tmp_A_b = FasterMul(A, b);
MulN2(tmp_A_b, n_2);
BigBinary tmp_B_b = FasterMul(B, b);
ret = Add(tmp_A_b, tmp_B_b);
}
else
{
for(int i = 0; i < n_2; i ++)
D.x.push_back(b.x[i]);
D.check0();
for(int i = n_2; i < b.size(); i ++)
C.x.push_back(b.x[i]);
C.check0();
BigBinary tmp_A_C = FasterMul(A, C);
BigBinary tmp_B_D = FasterMul(B, D);
BigBinary m_A_B = Minus(A, B);
BigBinary m_D_C = Minus(D, C);
BigBinary tmp_ABDC = FasterMul(m_A_B, m_D_C);
BigBinary ad_ACBD = Add(tmp_A_C, tmp_B_D);
BigBinary tmp_AD_BC = Add(tmp_ABDC, ad_ACBD);
MulN2(tmp_A_C, n_2 * 2);
MulN2(tmp_AD_BC, n_2);
BigBinary tmpACADBC = Add(tmp_A_C, tmp_AD_BC);
ret = Add(tmpACADBC, tmp_B_D);
}
ret.neg = a.neg ^ b.neg;
return ret;
}
const int maxn = 1e5 + 10;
char buf[maxn];
BigBinary a, b;
int main()
{
while(scanf("%s", buf) != EOF)
{
a.Init();
b.Init();
for(int i = strlen(buf) - 1; i >= 0; i --)
a.x.push_back(buf[i] == '1');
scanf("%s", buf);
for(int i = strlen(buf) - 1; i >= 0; i --)
b.x.push_back(buf[i] == '1');
FasterMul(a, b).Print();
}
return 0;
}
一个更容易写的方法:
事先对齐两数,前导0不影响计算结果
优化AD+BC的表示为(A+B)*(C+D)-AC-BD,代替(A-B)(D-C)+AC+BD,避免了减法出现负数
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<vector>
typedef std::vector<int> BigBinary;
void check(BigBinary &x)
{
while(!x.empty() && x.back() == 0) x.pop_back();
int cur = 0;
for(int i = 0; i < x.size(); i ++)
{
x[i] += cur;
// if(x[i] < 0) x[i + 1] += (x[i] - 1) / 2 - 1, x[i] = x[i] % 2 + 2;
cur = x[i] >> 1; x[i] &= 1;
}
for(; cur; cur >>= 1) x.push_back(cur & 1);
}
void Print(BigBinary &x)
{
check(x);
for(int i = x.size() - 1; i >= 0; i --) printf("%d", x[i]);
if(x.empty()) printf("0");
printf("\n");
}
BigBinary Add(const BigBinary &a, const BigBinary &b, int negFlag=1)
{
BigBinary c(a);
for(int i = 0; i < b.size(); i ++) c[i] += b[i] * negFlag;
return c;
}
BigBinary Minus(const BigBinary &a, const BigBinary &b)
{
return Add(a, b, -1); // 本算法保证了减法结果不小于0
}
BigBinary Mul(const BigBinary &a, const BigBinary &b)
{
BigBinary c;
c.resize(a.size() * b.size() + 1);
for(int i = 0; i < a.size(); i ++)
for(int j = 0; j < b.size(); j ++)
c[i + j] += a[i] * b[j];
return c;
}
void MulN2(BigBinary &a, int n_2)
{
int isize = a.size();
a.resize(isize + n_2);
for(int i = a.size() - 1, j = isize - 1; j >= 0; i --, j--)
a[i] = a[j];
for(int i = n_2 - 1; i >= 0; i --) a[i] = 0;
}
BigBinary FasterMul(const BigBinary &a, const BigBinary &b)
{
if(a.size() < 32) return Mul(a, b);
int n_2 = a.size() >> 1;
BigBinary A(a.begin() + n_2, a.end());
BigBinary B(a.begin(), a.begin() + n_2);
BigBinary C(b.begin() + n_2, b.end());
BigBinary D(b.begin(), b.begin() + n_2);
BigBinary A_C = FasterMul(A, C);
BigBinary B_D = FasterMul(B, D);
// AD+BC = (A+B)*(C+D)-AC-BD,该方式与课本不同,避免了减法出现负数
BigBinary ADpBC = Minus(Minus(FasterMul(Add(A, B), Add(C, D)), A_C), B_D);
MulN2(A_C, n_2 << 1); MulN2(ADpBC, n_2);
return Add(Add(A_C, ADpBC), B_D);
}
const int maxn = 1e5 + 10;
char buf[maxn];
BigBinary a, b;
#ifdef CPC
#include<time.h>
#endif
int main()
{
while(scanf("%s", buf) != EOF)
{
a.clear();
b.clear();
for(int i = strlen(buf) - 1; i >= 0; i --)
a.push_back(buf[i] == '1');
scanf("%s", buf);
for(int i = strlen(buf) - 1; i >= 0; i --)
b.push_back(buf[i] == '1');
if(a.size() < b.size()) a.resize(b.size(), 0);
else b.resize(a.size(), 0);
BigBinary res = FasterMul(a, b);
Print(res);
}
return 0;
}
转载自作者:坪河夜雨
链接:https://www.jianshu.com/p/4386cff19146
来源:简书