分治-整数位乘

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
来源:简书
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值