高精度模板

完整模板 1

作者:小黑AWM + MashPlant

注:可以直接把BigInt和int一样用cin、cout都行,就是高精乘为了速度才用了FFT降低了精度,有需要可以自行更改。

#include <cstdio>
#include <iostream>
#include <cmath>
#include <string>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const double PI = acos(-1.0);
struct Complex{
    double x,y;
    Complex(double _x = 0.0,double _y = 0.0){
        x = _x;
        y = _y;
    }
    Complex operator-(const Complex &b)const{
        return Complex(x - b.x,y - b.y);
    }
    Complex operator+(const Complex &b)const{
        return Complex(x + b.x,y + b.y);
    }
    Complex operator*(const Complex &b)const{
        return Complex(x*b.x - y*b.y,x*b.y + y*b.x);
    }
};
void change(Complex y[],int len){
    int i,j,k;
    for(int i = 1,j = len/2;i<len-1;i++){
        if(i < j)    swap(y[i],y[j]);
        k = len/2;
        while(j >= k){
            j = j - k;
            k = k/2;
        }
        if(j < k)    j+=k;
    }
}
void fft(Complex y[],int len,int on){
    change(y,len);
    for(int h = 2;h <= len;h<<=1){
        Complex wn(cos(on*2*PI/h),sin(on*2*PI/h));
        for(int j = 0;j < len;j += h){
            Complex w(1,0);
            for(int k = j;k < j + h/2;k++){
                Complex u = y[k];
                Complex t = w*y[k + h/2];
                y[k] = u + t;
                y[k + h/2] = u - t;
                w = w*wn;
            }
        }
    }
    if(on == -1){
        for(int i = 0;i < len;i++){
            y[i].x /= len;
        }
    }
}
class BigInt
{
#define Value(x, nega) ((nega) ? -(x) : (x))
#define At(vec, index) ((index) < vec.size() ? vec[(index)] : 0)
    static int absComp(const BigInt &lhs, const BigInt &rhs)
    {
        if (lhs.size() != rhs.size())
            return lhs.size() < rhs.size() ? -1 : 1;
        for (int i = lhs.size() - 1; i >= 0; --i)
            if (lhs[i] != rhs[i])
                return lhs[i] < rhs[i] ? -1 : 1;
        return 0;
    }
    using Long = long long;
    const static int Exp = 9;
    const static Long Mod = 1000000000;
    mutable std::vector<Long> val;
    mutable bool nega = false;
    void trim() const
    {
        while (val.size() && val.back() == 0)
            val.pop_back();
        if (val.empty())
            nega = false;
    }
    int size() const { return val.size(); }
    Long &operator[](int index) const { return val[index]; }
    Long &back() const { return val.back(); }
    BigInt(int size, bool nega) : val(size), nega(nega) {}
    BigInt(const std::vector<Long> &val, bool nega) : val(val), nega(nega) {}

public:
    friend std::ostream &operator<<(std::ostream &os, const BigInt &n)
    {
        if (n.size())
        {
            if (n.nega)
                putchar('-');
            for (int i = n.size() - 1; i >= 0; --i)
            {
                if (i == n.size() - 1)
                    printf("%lld", n[i]);
                else
                    printf("%0*lld", n.Exp, n[i]);
            }
        }
        else
            putchar('0');
        return os;
    }
    friend BigInt operator+(const BigInt &lhs, const BigInt &rhs)
    {
        BigInt ret(lhs);
        return ret += rhs;
    }
    friend BigInt operator-(const BigInt &lhs, const BigInt &rhs)
    {
        BigInt ret(lhs);
        return ret -= rhs;
    }
    BigInt(Long x = 0)
    {
        if (x < 0)
            x = -x, nega = true;
        while (x >= Mod)
            val.push_back(x % Mod), x /= Mod;
        if (x)
            val.push_back(x);
    }
    BigInt(const char *s)
    {
        int bound = 0, pos;
        if (s[0] == '-')
            nega = true, bound = 1;
        Long cur = 0, pow = 1;
        for (pos = strlen(s) - 1; pos >= Exp + bound - 1; pos -= Exp, val.push_back(cur), cur = 0, pow = 1)
            for (int i = pos; i > pos - Exp; --i)
                cur += (s[i] - '0') * pow, pow *= 10;
        for (cur = 0, pow = 1; pos >= bound; --pos)
            cur += (s[pos] - '0') * pow, pow *= 10;
        if (cur)
            val.push_back(cur);
    }
    BigInt &operator=(const char *s){
        BigInt n(s);
        *this = n;
        return n;
    }
    BigInt &operator=(const Long x){
        BigInt n(x);
        *this = n;
        return n;
    }
    friend std::istream &operator>>(std::istream &is, BigInt &n){
        string s;
        is >> s;
        n=(char*)s.data();
        return is;
    }
    BigInt &operator+=(const BigInt &rhs)
    {
        const int cap = std::max(size(), rhs.size()) + 1;
        val.resize(cap);
        int carry = 0;
        for (int i = 0; i < cap - 1; ++i)
        {
            val[i] = Value(val[i], nega) + Value(At(rhs, i), rhs.nega) + carry, carry = 0;
            if (val[i] >= Mod)
                val[i] -= Mod, carry = 1;
            else if (val[i] < 0)
                val[i] += Mod, carry = -1;
        }
        if ((val.back() = carry) == -1) //assert(val.back() == 1 or 0 or -1)
        {
            nega = true, val.pop_back();
            bool tailZero = true;
            for (int i = 0; i < cap - 1; ++i)
            {
                if (tailZero && val[i])
                    val[i] = Mod - val[i], tailZero = false;
                else
                    val[i] = Mod - 1 - val[i];
            }
        }
        trim();
        return *this;
    }
    friend BigInt operator-(const BigInt &rhs)
    {
        BigInt ret(rhs);
        ret.nega ^= 1;
        return ret;
    }
    BigInt &operator-=(const BigInt &rhs)
    {
        rhs.nega ^= 1;
        *this += rhs;
        rhs.nega ^= 1;
        return *this;
    }
    friend BigInt operator*(const BigInt &lhs, const BigInt &rhs)
    {
        int len=1;
        BigInt ll=lhs,rr=rhs;
        ll.nega = lhs.nega ^ rhs.nega;
        while(len<2*lhs.size()||len<2*rhs.size())len<<=1;
        ll.val.resize(len),rr.val.resize(len);
        Complex x1[len],x2[len];
        for(int i=0;i<len;i++){
            Complex nx(ll[i],0.0),ny(rr[i],0.0);
            x1[i]=nx;
            x2[i]=ny;
        }
        fft(x1,len,1);
        fft(x2,len,1);
        for(int i = 0 ; i < len; i++)
            x1[i] = x1[i] * x2[i];
        fft( x1 , len , -1 );
        for(int i = 0 ; i < len; i++)
            ll[i] = int( x1[i].x + 0.5 );
        for(int i = 0 ; i < len; i++){
            ll[i+1]+=ll[i]/Mod;
            ll[i]%=Mod;
        }
        ll.trim();
        return ll;
    }
    friend BigInt operator*(const BigInt &lhs, const Long &x){
        BigInt ret=lhs;
        bool negat = ( x < 0 );
        Long xx = (negat) ? -x : x;
        ret.nega ^= negat;
        ret.val.push_back(0);
        ret.val.push_back(0);
        for(int i = 0; i < ret.size(); i++)
            ret[i]*=xx;
        for(int i = 0; i < ret.size(); i++){
            ret[i+1]+=ret[i]/Mod;
            ret[i] %= Mod;
        }
        ret.trim();
        return ret;
    }
    BigInt &operator*=(const BigInt &rhs) { return *this = *this * rhs; }
    BigInt &operator*=(const Long &x) { return *this = *this * x; }
    friend BigInt operator/(const BigInt &lhs, const BigInt &rhs)
    {
        static std::vector<BigInt> powTwo{BigInt(1)};
        static std::vector<BigInt> estimate;
        estimate.clear();
        if (absComp(lhs, rhs) < 0)
            return BigInt();
        BigInt cur = rhs;
        int cmp;
        while ((cmp = absComp(cur, lhs)) <= 0)
        {
            estimate.push_back(cur), cur += cur;
            if (estimate.size() >= powTwo.size())
                powTwo.push_back(powTwo.back() + powTwo.back());
        }
        if (cmp == 0)
            return BigInt(powTwo.back().val, lhs.nega ^ rhs.nega);
        BigInt ret = powTwo[estimate.size() - 1];
        cur = estimate[estimate.size() - 1];
        for (int i = estimate.size() - 1; i >= 0 && cmp != 0; --i)
            if ((cmp = absComp(cur + estimate[i], lhs)) <= 0)
                cur += estimate[i], ret += powTwo[i];
        ret.nega = lhs.nega ^ rhs.nega;
        return ret;
    }
    friend BigInt operator/(const BigInt &num,const Long &x){
        bool negat = ( x < 0 );
        Long xx = (negat) ? -x : x;
        BigInt ret;
        Long k = 0;
        ret.val.resize( num.size() );
        ret.nega = (num.nega ^ negat);
        for(int i = num.size() - 1 ;i >= 0; i--){
            ret[i] = ( k * Mod + num[i]) / xx;
            k = ( k * Mod + num[i]) % xx;
        }
        ret.trim();
        return ret;
    }
    bool operator==(const BigInt &rhs) const
    {
        return nega == rhs.nega && val == rhs.val;
    }
    bool operator!=(const BigInt &rhs) const { return nega != rhs.nega || val != rhs.val; }
    bool operator>=(const BigInt &rhs) const { return !(*this < rhs); }
    bool operator>(const BigInt &rhs) const { return !(*this <= rhs); }
    bool operator<=(const BigInt &rhs) const
    {
        if (nega && !rhs.nega)
            return true;
        if (!nega && rhs.nega)
            return false;
        int cmp = absComp(*this, rhs);
        return nega ? cmp >= 0 : cmp <= 0;
    }
    bool operator<(const BigInt &rhs) const
    {
        if (nega && !rhs.nega)
            return true;
        if (!nega && rhs.nega)
            return false;
        return (absComp(*this, rhs) < 0) ^ nega;
    }
    void swap(const BigInt &rhs) const
    {
        std::swap(val, rhs.val);
        std::swap(nega, rhs.nega);
    }
};
BigInt ba,bb;
int main(){
    cin>>ba>>bb;
    cout << ba + bb << '\n';    // 和
    cout << ba - bb << '\n';    // 差
    cout << ba * bb << '\n';    // 积
    BigInt d;
    cout << (d = ba / bb) << '\n';    // 商
    cout << ba - d * bb << '\n';    // 余
    return 0;
}

完整模板 2

(真正“拷贝下来就能运行”的高精度模板)

主要结构、赋值模块、比较模块、加法运算模块、输入输出重载均出自刘汝佳《算法竞赛入门经典(第 2 版)》。

原书使用的结构体名为 BigInteger,名字出自 Java 语言定义的 BigInteger 类。这里代码将结构体名称简化为 big。

  • 我添加了减法模块,允许负数计算;(2017-8-9)

  • 乘法模块已添加,允许负数计算;(2017-8-11)

  • 除法模块已添加(大除小);(2017-10-20)

  • 或许可以添加乘方、开方(如 Luogu 2293 [HNOI2004]高精度开根)、膜法等模块,暂时不考虑(长期坑)。(2017-8-10)

这里有一份拥有除法、膜法的 BigInteger 代码:Link link,只允许大数在前,小数在后。

对于高精度算法的“特殊优化”在文章最后面。

/**
 * struct big
 * Au: GG
 * Last modified: October 20, 2017
 */

#define DEBUG printf("Passing [%s] in LINE %d\n",__FUNCTION__,__LINE__)
#include <bits/stdc++.h>

struct big {
    static const int BASE = 10000;   // 当只使用加减法时可以节省空间,把
    static const int WIDTH = 4;      // BASE 改成 100000000,WIDTH 改成 8
    std::vector<int> s;

    big(long long num = 0) { *this = num; }
    big(const std::string& str) { *this = str; }
    big operator = (long long num) {
        s.clear();
        do {
            s.push_back(num % BASE);
            num /= BASE;
        } while (num > 0);
        return *this;
    }
    big operator = (const std::string& str) {
        s.clear();
        int x, len = (str.length() - 1) / WIDTH + 1;
        for (int i = 0; i < len; i++) {
            int end = str.length() - i * WIDTH;
            int start = std::max(0, end - WIDTH);
            sscanf(str.substr(start, end - start).c_str(), "%d", &x);
            s.push_back(x);
        }
        return *this;
    }

    bool operator < (const big& b) const {
        if (s.size() != b.s.size()) return s.size() < b.s.size();
        for (int i = s.size() - 1; i >= 0; i--)
            if (s[i] != b.s[i]) return s[i] < b.s[i];
        return false;
    }
    bool operator > (const big& b) const { return b < *this; }
    bool operator <= (const big& b) const { return !(b < *this); }
    bool operator >= (const big& b) const { return !(*this < b); }
    bool operator != (const big& b) const { return b < *this || *this < b; }
    bool operator == (const big& b) const { return !(b < *this) && !(*this < b); }

    big operator + (const big& b) const {
        big c;
        c.s.clear();
        for (int i = 0, g = 0; ; i++) {
            if (g == 0 && i >= s.size() && i >= b.s.size()) break;
            int x = g;
            if (i < s.size()) x += s[i];
            if (i < b.s.size()) x += b.s[i];
            c.s.push_back(x % BASE);
            g = x / BASE;
        }
        return c;
    }
    big operator - (const big& b) const {
        big c;
        c.s.clear();
        if (*this == b) {
            c.s.push_back(0);
        } else if (*this < b) {
            for (int i = 0, g = 0; ; i++) {
                if (g == 0 && i >= b.s.size() && i >= s.size()) {
                    c.s[i - 1] = -c.s[i - 1]; break;
                }
                int x = g;
                if (i < b.s.size()) x += b.s[i];
                if (i < s.size()) x -= s[i];
                if (x < 0) {
                    c.s.push_back(BASE + x % BASE);
                    g = x / BASE - 1;
                } else {
                    c.s.push_back(x % BASE);
                    g = x / BASE;
                }
            }
        } else {
            for (int i = 0, g = 0; ; i++) {
                if (g == 0 && i >= s.size() && i >= b.s.size()) break;
                int x = g;
                if (i < s.size()) x += s[i];
                if (i < b.s.size()) x -= b.s[i];
                if (x < 0) {
                    c.s.push_back(BASE + x % BASE);
                    g = x / BASE - 1;
                } else {
                    c.s.push_back(x % BASE);
                    g = x / BASE;
                }
            }
        }
        return c;
    }

    big operator * (const big& b) const {
        big c; int len = s.size() + b.s.size(); bool flag = false;
        c.s.clear();
        if (*this == 0 || b == 0) {c.s.push_back(0); return 0;}
        if (*this < 0 && b > 0) flag = true;
        if (*this > 0 && b < 0) flag = true;
        for (int i = 0, g = 0; ; i++) {
            if (g == 0 && i >= len) break;
            int x = g;
            for (int u = 0, v = i, temp; v >= 0; u++, v--)
                if (u < s.size() && v < b.s.size()) {
                    temp = s[u] * b.s[v];
                    if (temp < 0) temp = -temp;
                    x += temp;
                }
            c.s.push_back(x % BASE);
            g = x / BASE;
        }
        for (int i = c.s.size() - 1; i >= 0 && c.s[i] == 0; i--)
            c.s.pop_back();
        if (flag) c.s[c.s.size() - 1] = -c.s[c.s.size() - 1];
        return c;
    }

    inline void killzero() {
        while (s.back() == 0 && s.size() > 1) s.pop_back();
    }
    inline void reverse() {
        int len = s.size();
        for (int i = 0; i < len >> 1; ++i) swap(s[i], s[len - i - 1]);
    }

    big operator / (const big &b) const {
		big c, t;
		c.s.clear(); t.s.clear();
		for (int i = s.size() - 1; i >= 0; --i) {
			t.s.push_back(s[i]);
			int x = 0;
			while (b <= t) { t -= b; x++; }
			c.s.push_back(x);
		}
		c.reverse();
		c.killzero();
		return c;
	}

    big operator += (const big& b) {
        *this = *this + b; return *this;
    }
    big operator ++ (int) {
        *this = *this + 1; return *this;
    }
    big operator ++ () {
        *this = *this + 1; return *this;
    }
    big operator -= (const big& b) {
        *this = *this - b; return *this;
    }
    big operator -- (int) {
        *this = *this - 1; return *this;
    }
    big operator -- () {
        *this = *this - 1; return *this;
    }
    big operator *= (const big& b) {
        *this = *this * b; return *this;
    }
    big operator /= (const big& b) {
        *this = *this / b; return *this;
    }
    // big operator %= (const big& b) {
    //     *this = *this % b; return *this;
    // }
};

std::ostream& operator << (std::ostream& out, const big& x) {
    out << x.s.back();
    for (int i = x.s.size() - 2; i >= 0; i--) {
        char buf[20];
        sprintf(buf, "%04d", x.s[i]);
        for (int j = 0; j < strlen(buf); j++) out << buf[j];
    }
    return out;
}
std::istream& operator >> (std::istream& in, big& x) {
    std::string s;
    if (!(in >> s)) return in;
    x = s;
    return in;
}

int main() {
    big alpha, beta;
    std::cin >> alpha >> beta;
    std::cout << alpha * beta << std::endl;
    return 0;
}

高精度模板的专项优化

乘法(优化时间复杂度)

例子:Luogu 1303 A*B Problem

  • 消灭了结构体,函数全塞 main 里;

  • 读入采用 scanf;

  • 数组开超级大,再搞几个指针。

终于卡过了时限,结束 TLE 的悲惨命运。

/* P1303 A*B Problem
 * Au: GG
 */
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;

int a[5000], at, b[5000], bt, c[5000], ct;

int main() {
    char sa[5000], sb[5000], sc[5000];
    scanf("%s", sa);
    scanf("%s", sb);
    for (int i = strlen(sa) - 1; i >= 0; i--)
        a[at++] = sa[i] - '0';
    for (int i = strlen(sb) - 1; i >= 0; i--)
        b[bt++] = sb[i] - '0';

    int len = at + bt;
    for (int i = 0, g = 0; ; i++) {
        if (g == 0 && i >= len) break;
        int x = g;
        for (int u = 0, v = i; v >= 0; u++, v--)
            if (u < at && v < bt) {
                x += a[u] * b[v];
            }
        c[ct++] = x % 10;
        g = x / 10;
    }
    while (c[ct - 1] == 0 && ct > 1) ct--;

    printf("%d", c[ct - 1]);
    for (int i = ct - 2; i >= 0; i--) {
        printf("%d", c[i]);
    }
    printf("\n");
    return 0;
}

国王游戏

/* 国王游戏
 * Au: GG
 */
#include <bits/stdc++.h>
using namespace std;

const int N = 1000 + 3;

int o, u, i, n;

struct node {
	string l, r, s;
} d[N], sum, ans, res;

string divide(string a, string b) {
	string c;
	int d = 0, k = 1, p = 0;
	for (o = 0; o < a.length(); o++) a[o] -= '0';
	for (o = b.length() - 1; o + 1; o--) p += (b[o] - '0') * k, k *= 10;
	for (o = 0; o < a.length(); o++)
		c.push_back((d * 10 + a[o]) / p + '0'), d = (d * 10 + a[o]) % p;
	while (c[0] == '0') c.erase(c.begin(), c.begin() + 1);
	return c;
}
string times(string a, string b) {
	string c;
	c.resize(a.length() + b.length(), 0);
	reverse(a.begin(), a.end());
	reverse(b.begin(), b.end());
	for (o = 0; o < a.length(); o++) a[o] -= '0';
	for (o = 0; o < b.length(); o++) b[o] -= '0';
	for (o = 0; o < a.length(); o++)
		for (u = 0; u < b.length(); u++)
			c[o + u] += a[o] * b[u], c[o + u + 1] += c[o + u] / 10, c[o + u] %= 10;
	reverse(c.begin(), c.end());
	while (!c[0]) c.erase(c.begin(), c.begin() + 1);
	for (o = 0; o < c.length(); o++) c[o] += '0';
	return c;
}
bool cmp(node a, node b) {
	if (a.s.length() < b.s.length()) return 1;
	if (b.s.length() < a.s.length()) return 0;
	return a.s < b.s;
}

int main() {
	ios::sync_with_stdio(false);
	cin >> n; sum.s = "1", ans.s = "0";
	for (int i = 0; i <= n; i++) {
		cin >> d[i].l >> d[i].r;
		d[i].s = times(d[i].l, d[i].r);
	}
	sort(d + 1, d + n + 1, cmp);

	for (int i = 0; i <= n; i++) {
		res.s = divide(sum.s, d[i].r);
		if (cmp(ans, res)) ans = res;
		sum.s = times(sum.s, d[i].l);
	}

	cout << ans.s << endl;
	return 0;
}
posted @ 2017-08-09 12:16  greyqz  阅读(743)  评论(0编辑  收藏  举报