高精度学习笔记

高精度学习笔记

这玩意真难记

先上总代码

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
typedef int int_;
#define int long long
const int base = 1e8;

using namespace std;

char str1[60000], str2[60000];

struct Int{
    vector<int> val;
    Int()
    {
        val.clear();
        val.resize(1, 0);
    }
    Int(char *str)
    {
        int len = strlen(str);
        int ret = 0, b = 1;
        for(int i = len - 1; i >= 0; i--)
        {
            ret += (str[i] - 48) * b;
            b *= 10;
            if((len - i) % 8 == 0)
            {
                val.push_back(ret);
                ret = 0, b = 1;
            }
        }
        val.push_back(ret);
        return ;
    }
    void clear()
    {
        while(!val.back() && val.size() > 1) val.pop_back();
    }
    int cmp(Int b)
    {
        Int a = *this, c;
        int len1 = a.val.size();
        int len2 = b.val.size();
        if(len1 < len2) return -1;
        else if(len1 > len2) return 1;
        else 
            for(int i = len1 - 1; i >= 0; i--)
            {
                if(a.val[i] < b.val[i]) return -1;
                else if(a.val[i] > b.val[i]) return 1;
            }
        return 1;
    }
    bool operator<(Int b)
    {
        Int a = *this;
        return a.cmp(b) < 0;
    }
    bool operator>(Int b)
    {
        Int a = *this;
        return a.cmp(b) > 0;
    }
    bool operator==(Int b)
    {
        Int a = *this;
        return a.cmp(b) == 0;
    }
    Int operator+(Int b)
    {
        Int a = *this, c;
        int len1 = a.val.size();
        int len2 = b.val.size();
        int len3 = max(len1, len2) + 1;
        c.val.resize(len3, 0);
        for(int i = 0; i < len3; i++)
        {
            if(i < len1) c.val[i] += a.val[i];
            if(i < len2) c.val[i] += b.val[i];
        }
        for(int i = 0; i < len3 - 1; i++)
        {
            c.val[i + 1] += c.val[i] / base;
            c.val[i] %= base;
        }
        c.clear();
        return c;
    }
    Int operator-(Int b)
    {
        Int a = *this, c;
        bool flag = 0;
        if(a < b)
        {
            swap(a, b);
            flag = 1;
        }
        int len1 = a.val.size();
        int len2 = b.val.size();
        int len3 = len1;
        c.val.resize(len3, 0);
        for(int i = 0; i < len3; i++)
            c.val[i] = a.val[i] - (i < len2 ? b.val[i] : 0);
        for(int i = 0; i < len3 - 1; i++)
        {
            if(c.val[i] < 0)
            {
                c.val[i] += base;
                c.val[i + 1]--;
            }
        }
        c.clear();
        if(flag) c.val.back() = -c.val.back();
        return c;
    }
    Int operator*(Int b)
    {
        Int a = *this, c;
        int len1 = a.val.size();
        int len2 = b.val.size();
        int len3 = len1 + len2;
        c.val.resize(len3, 0);
        for(int i = 0; i < len1; i++)
            for(int j = 0; j < len2; j++)
                c.val[i + j] += a.val[i] * b.val[j];
        for(int i = 0; i < len3 - 1; i++)
        {
            c.val[i + 1] += c.val[i] / base;
            c.val[i] %= base;
        }
        c.clear(); 
        return c;
    }
    Int operator/(Int temp)
    {
        int b = temp.val[0];
        Int a = *this, c;
        int len = a.val.size();
        c.val.resize(len, 0);
        for(int i = len - 1; i >= 1; i--)
        {
            c.val[i] = a.val[i] / b;
            a.val[i - 1] += a.val[i] % b * base;
        }
        c.val[0] = a.val[0] / b;
        c.clear();
        return c;
    }
    void output()
    {
        int len = val.size();
        printf("%lld", val[len - 1]);
        for(int i = len - 2; i >= 0; i--)
        {
            printf("%08lld", val[i]);
        }
    }
};

int_ main() {
    scanf("%s%s", str1, str2);
    Int a(str1), b(str2), c;
    c = a + b;
    c.output();
    puts("");
    c = a - b;
    c.output();
    puts("");
    c = a * b;
    c.output();
    puts("");
    c = a / b;
    c.output();
    puts("");
    return 0;
}

上面的代码包括了 高精加 减 乘高精 以及 高精低精


前置

vector<int> val;
    Int()
    {
        val.clear();
        val.resize(1, 0);
    }
    Int(char *str)
    {
        int len = strlen(str);
        int ret = 0, b = 1;
        for(int i = len - 1; i >= 0; i--)
        {
            ret += (str[i] - 48) * b;
            b *= 10;
            if((len - i) % 8 == 0)
            {
                val.push_back(ret);
                ret = 0, b = 1;
            }
        }
        val.push_back(ret);
        return ;
    }

我们定义一种 Int 代表高精类型

在定义变量时,如果单纯定义一个变量,就为它开一个长度为1的数组并将val[0]设为0

如果这个变量由字符串转换而来则将它每八位拆为一组,倒叙压入vector

void clear()
    {
        while(!val.back() && val.size() > 1) val.pop_back();
    }

这段代码是消除前导0,但保存最后一个0


加法

Int operator+(Int b)
    {
        Int a = *this, c;
        int len1 = a.val.size();
        int len2 = b.val.size();
        int len3 = max(len1, len2) + 1;
        c.val.resize(len3, 0);
        for(int i = 0; i < len3; i++)
        {
            if(i < len1) c.val[i] += a.val[i];
            if(i < len2) c.val[i] += b.val[i];
        }
        for(int i = 0; i < len3 - 1; i++)
        {
            c.val[i + 1] += c.val[i] / base;
            c.val[i] %= base;
        }
        c.clear();
        return c;
    }

重载运算符 +

如我们计算1 + 2

则此时b就是2;

*this 则是加号前面的变量('1')

c.val来储存结果

用普通加法将每一位的和储存, 最后再模拟10进制进位


乘法

Int operator*(Int b)
    {
        Int a = *this, c;
        int len1 = a.val.size();
        int len2 = b.val.size();
        int len3 = len1 + len2;
        c.val.resize(len3, 0);
        for(int i = 0; i < len1; i++)
            for(int j = 0; j < len2; j++)
                c.val[i + j] += a.val[i] * b.val[j];
        for(int i = 0; i < len3 - 1; i++)
        {
            c.val[i + 1] += c.val[i] / base;
            c.val[i] %= base;
        }
        c.clear(); 
        return c;
    }

乘法和加法差不多

要注意位数最大是a的位数加上b的位数

在保存每一位相乘的值时,我们可以手动模拟竖式乘法计算

然后就能得出保存的位置应在i + j的位置

剩下操作与加法相同


减法

    Int operator-(Int b)
    {
        Int a = *this, c;
        bool flag = 0;
        if(a < b)
        {
            swap(a, b);
            flag = 1;
        }
        int len1 = a.val.size();
        int len2 = b.val.size();
        int len3 = len1;
        c.val.resize(len3, 0);
        for(int i = 0; i < len3; i++)
            c.val[i] = a.val[i] - (i < len2 ? b.val[i] : 0);
        for(int i = 0; i < len3 - 1; i++)
        {
            if(c.val[i] < 0)
            {
                c.val[i] += base;
                c.val[i + 1]--;
            }
        }
        c.clear();
        if(flag) c.val.back() = -c.val.back();
        return c;
    }

减法由于需要判断正负,我们在开始便设一个flag标记,如果被减数小于减数便互换位置并且flag = 1

第一个for循环中,我们使用一个三目运算符来判断,如果这位已经没有值了就减0

借位看代码就懂了;

最后如果flag = 1就让最开始的8位数字变负


除法(高精除高精太难写不会

    Int operator/(Int temp)
    {
        int b = temp.val[0];
        Int a = *this, c;
        int len = a.val.size();
        c.val.resize(len, 0);
        for(int i = len - 1; i >= 1; i--)
        {
            c.val[i] = a.val[i] / b;
            a.val[i - 1] += a.val[i] % b * base;
        }
        c.val[0] = a.val[0] / b;
        c.clear();
        return c;
    }

看起来短实际。。。

最后只要整除即可所以最后的c.val[0]就不管余数了


高精比较大小

int cmp(Int b)
    {
        Int a = *this, c;
        int len1 = a.val.size();
        int len2 = b.val.size();
        if(len1 < len2) return -1;
        else if(len1 > len2) return 1;
        else 
            for(int i = len1 - 1; i >= 0; i--)
            {
                if(a.val[i] < b.val[i]) return -1;
                else if(a.val[i] > b.val[i]) return 1;
            }
        return 1;
    }
    bool operator<(Int b)
    {
        Int a = *this;
        return a.cmp(b) < 0;
    }
    bool operator>(Int b)
    {
        Int a = *this;
        return a.cmp(b) > 0;
    }
    bool operator==(Int b)
    {
        Int a = *this;
        return a.cmp(b) == 0;
    }

例题 国王游戏

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
typedef int int_;
#define int long long
const int base = 1e8;

using namespace std;

char str1[60000], str2[60000];

struct Int{
    int l, r, sum;
    vector<int> val;
    Int()
    {
        val.clear();
        val.resize(1, 0);
    }
    Int(char *str)
    {
        int len = strlen(str);
        int ret = 0, b = 1;
        for(int i = len - 1; i >= 0; i--)
        {
            ret += (str[i] - 48) * b;
            b *= 10;
            if((len - i) % 8 == 0)
            {
                val.push_back(ret);
                ret = 0, b = 1;
            }
        }
        val.push_back(ret);
        return ;
    }
    void clear()
    {
        while(!val.back() && val.size() > 1) val.pop_back();
    }
    int cmp(Int b)
    {
        Int a = *this, c;
        int len1 = a.val.size();
        int len2 = b.val.size();
        if(len1 < len2) return -1;
        else if(len1 > len2) return 1;
        else 
            for(int i = len1 - 1; i >= 0; i--)
            {
                if(a.val[i] < b.val[i]) return -1;
                else if(a.val[i] > b.val[i]) return 1;
            }
        return 1;
    }
    bool operator<(Int b)
    {
        Int a = *this;
        return a.cmp(b) < 0;
    }
    bool operator>(Int b)
    {
        Int a = *this;
        return a.cmp(b) > 0;
    }
    bool operator==(Int b)
    {
        Int a = *this;
        return a.cmp(b) == 0;
    }
    Int operator*(const int b)
    {
        Int a = *this, c;
        int len1 = a.val.size();
        int len3 = len1 + 10;
        c.val.resize(len3, 0);
        for(int i = 0; i < len1; i++)
                c.val[i] += a.val[i] * b;
        for(int i = 0; i < len3 - 1; i++)
        {
            c.val[i + 1] += c.val[i] / base;
            c.val[i] %= base;
        }
        c.clear(); 
        return c;
    }
    Int operator/(const int b)
    {
        Int a = *this, c;
        int len = a.val.size();
        c.val.resize(len, 0);
        for(int i = len - 1; i >= 1; i--)
        {
            c.val[i] = a.val[i] / b;
            a.val[i - 1] += a.val[i] % b * base;
        }
        c.val[0] = a.val[0] / b;
        c.clear();
        return c;
    }
    void output()
    {
        int len = val.size();
        printf("%lld", val[len - 1]);
        for(int i = len - 2; i >= 0; i--)
        {
            printf("%08lld", val[i]);
        }
    }
}arr[1050];

int cmp(const Int s1,const Int s2)
{
    return s1.sum < s2.sum;
}

int n;

int_ main() {
    scanf("%lld",&n);
    for(int i = 0; i <= n; i++)
    {
        scanf("%lld%lld",&arr[i].l,&arr[i].r);
        arr[i].sum = arr[i].l * arr[i].r;
    }
    sort(arr + 1, arr + 1 + n,cmp);
    Int ans, tl, temp;
    tl.val[0] = 1;
    for(int i = 0; i < n; i++)
    {
        tl = tl * arr[i].l;
        temp = tl / arr[i + 1].r;
        if(temp > ans)
            ans = temp;
    }
    ans.output();
    return 0;
}

如果理解了高精度思想很容易就能看懂

这题数学证明的出双手数字乘积越大越往后排

具体怎么证不写了

有一点害我调了很久连样例过不了

resize并不会对原vector已经存在的元素进行重新初始化!!!!!

所以最后改直接给val[0]赋值了,然后就ac了

猜你喜欢

转载自www.cnblogs.com/wyswyz/p/11253531.html