zoukankan      html  css  js  c++  java
  • 高精度学习笔记

    高精度学习笔记

    先上总代码

    #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了

  • 相关阅读:
    mysql日期转化
    跳来跳去,到底去大公司还是小公司?
    年度重大升级,IntelliJ IDEA 2019.2 稳定版发布
    3年Java,鏖战腾讯
    重磅!挑战Oracle,华为将开源 GaussDB 数据库
    厉害了,Java EE 再次更名为 Jakarta EE
    彻底干掉恶心的 SQL 注入漏洞, 一网打尽!
    PostgreSQL 荣获 2019 年 O'Reilly 终身成就奖
    Intellij IDEA 智能补全的 10 个姿势,简直不能太牛逼!
    注意,千万不要打断工作中的程序员
  • 原文地址:https://www.cnblogs.com/wyswyz/p/11253531.html
Copyright © 2011-2022 走看看