• 高精度模板【重载运算符+压位】


    昨天做一道DP的题(矩阵取数游戏),本来是很简单的,但是要用高精度,又不想用__int128水过去(谁让NOIP不让),于是自己打了一个小时,最后成功挂了。。。

    于是本蒟蒻痛定思痛,感觉高精度还是重载运算符好用啊,就花了几个小时打了一个自以为比较好记好用高精度模板:

    注意暂不支持负数,如果发现有bug欢迎指出。

    /*采用重载运算符,压B位
    支持高精数赋值与输出、高精加(减)高精、高精乘低(高)精、高精除(模)低精、高精的比较 
    注意:暂不支持负数!!!*/
    #include<cstdio>
    #include<cstring>
    #include<stack>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long LL;
    const int N=128,B=4;
    const LL base=1e4;//压B位,base为1eB 
    struct HP{
    private:
        int len;LL a[N];
        inline void clear(){while(!a[len]&&len>1) --len;}//清除前导0 
    public:
        HP(){ //结构体初始化 
            memset(a,0ll,sizeof a);len=0;
        }    
        //注意因为是压B位的,所以输出要特殊处理 
        void print(){//输出高精度数 
            printf("%lld",a[len]);
            for(int i=len-1;i>0;--i)
                for(int j=base/10;j>0;j/=10) printf("%lld",a[i]/j%10);
            puts("");
        }
        /*以下是重载运算符*/ 
        HP& operator =(LL x){//用LL初始化高精度数    HP后加了&才可以实现像a=b=c这样连续赋值 
            stack<char> st;string s;
            if(!x) return *this="0";
            while(x){
                st.push(x%10+'0');
                x/=10;
            }
            while(!st.empty()) s+=st.top(),st.pop();//其实就是把int转换为string再调用init_s()
            return *this=s;
        }
        HP& operator =(const string &s){//用string初始化高精度数
            memset(a,0ll,sizeof a);len=0;//这里赋值为0才可以保证重复赋值时不会出锅。。。 
            int l=s.length();
            for(int i=0;i<=l;++i){
                int j=(l-i+(B-1))/B;//因为压B位所以要特殊处理 
                a[j]=(a[j]<<1)+(a[j]<<3)+(s[i]^48);
            }
            len=(l+(B-1))/B;
            return *this;
        } 
        HP operator +(const HP &x)const{//高精加高精 
            HP res;res.len=max(len,x.len);LL k=0ll;
            for(int i=1;i<=res.len;++i){
                res.a[i]=a[i]+x.a[i]+k;
                k=res.a[i]/base;
                res.a[i]%=base;
            }
            if(k>0) res.a[++res.len]=k;
            return res;
        }
        HP operator -(const HP &x)const{//高精减高精(注意这里默认被减数大于减数,否则会出错) 
            HP res=*this;//相当于用res拷贝被减数 
            for(int i=1;i<=len;++i){
                res.a[i]-=x.a[i];
                if(res.a[i]<0) --res.a[i+1],res.a[i]+=base;
            }
            res.clear();
            return res;
        }
        HP operator *(const LL &x)const{//高精乘低精 
            HP res=*this;
            for(int i=1;i<=len;++i) res.a[i]*=x;
            for(int i=1;i<=len;++i) res.a[i+1]+=res.a[i]/base,res.a[i]%=base;
            int &end=res.len;
            while(res.a[end+1]>0){++end;res.a[end+1]+=res.a[end]/base,res.a[end]%=base;}
            return res; 
        }
        HP operator *(const HP &x)const{//高精乘高精 
            HP res;res.len=len+x.len;
            for(int i=1;i<=len;++i)
                for(int j=1;j<=x.len;++j){
                    res.a[i+j-1]+=a[i]*x.a[j];
                    res.a[i+j]+=res.a[i+j-1]/base;
                    res.a[i+j-1]%=base;
                }
            res.clear();
            return res;
        }
        HP operator /(const LL &x)const{//高精除低精 
            HP res;res.len=len;LL k=0ll;
            for(int i=len;i>0;--i){
                k=k*base+a[i];
                res.a[i]=k/x;
                k%=x;
            }
            res.clear();
            return res;
        }
        LL operator %(const LL &x)const{//高精模低精 
            LL k=0ll;
            for(int i=len;i>0;--i){
                k=k*base+a[i];
                k%=x;
            }
            return k;//其实跟高精除低精差不多的,只不过不用存res,返回的是k 
        }
        bool operator <(const HP &x)const{//重载小于号
            if(len==x.len){ 
                int i;
                for(i=len;a[i]==x.a[i]&&i>1;--i);
                if(i>=1) return a[i]<x.a[i];
                else return false;
            }
            else return len<x.len;
        }
        bool operator >(const HP &x)const{//重载大于号 
            if(len==x.len){ 
                int i;
                for(i=len;a[i]==x.a[i]&&i>1;--i);
                if(i>=1) return a[i]>x.a[i];
                else return false;
            }
            else return len>x.len;
        }
        //其实一般大于和小于号重载一个就够用了 
    };
    HP max(const HP &a,const HP &b){
        if(a>b) return a;
        return b;
    }
    HP min(const HP &a,const HP &b){
        if(a<b) return a;
        return b;
    }
    HP a,b,ans;
    string sa,sb;
    int main()
    {
        cin>>sa>>sb;
        a=sa,b=sb;
        ans=a*b;
        ans.print();
        return 0; 
    }
    View Code

    这里是压的4位,可以改B和base变成压B位。

    想粘板子就粘吧,打得丑我承认。


    Update on 11.3

    在打模拟题时我自己就发现了几个bug:

    (1)重载赋值运算符时,需要特判x=0的情况,不然无法赋值为0

    (2)不能用unsigned long long,因为高精减时一旦减出负数unsigned long long就会溢出,然后就出锅了(我太菜了这都没发现)。。。因此最好用long long

    (3)高精除与高精模,当除数很大时(接近long long的极大值)很容易溢出,这时运算过程中可能出现的最大位数为(压的位数+除数的位数),因此这个时候就应酌情减少压的位数了

    以上bug直接导致我那题100->75。。。

    2018-10-20

  • 相关阅读:
    luogu 2478 [SDOI2010]城市规划 仙人掌上dp.
    bzoj 3782 上学路线 卢卡斯定理 容斥 中国剩余定理 dp
    bzoj 3790 神奇项链 回文串 manacher|PAM
    4.4 相交弧 容斥 平衡规划 二维数点
    4.4 省选模拟赛 拉格朗日计数 树状数组+容斥.
    4.4 省选模拟赛 修路 斯坦纳树
    带修改线性基
    CF R 630 div2 1332 F Independent Set
    4.3 省选模拟赛 石子游戏 树上博弈
    机器C盘临时区
  • 原文地址:https://www.cnblogs.com/gosick/p/9822197.html
Copyright © 2020-2023  润新知