高精度 前缀和 差分


一 高精度

1.高精度加法

算法思想:模拟

可以用一个动态数组来存放相加后的元素,由于用数组存放,则函数会返回一个数组,在这里,可以用auto(编译器自动识别返回值类型)来代替vector,比较简便

代码实现:法一

vector<int> add(vector<int>& A, vector<int>& B)//大数加小数
{
	vector<int> C;
	if (A.size() < B.size()) return add(B, A);//如果数A小于数B,则返会B+A
	int t = 0;//t表示进位,初始化为0
	for (int i = 0; i < A.size(); i++)
	{
		t += A[i];
		if (i < B.size()) t += B[i];//如果B的位数存在的话,继续相加
		C.push_back(t % 10);
		t /= 10;
	}
	if (t) C.push_back(1);//如果最终t不为0,说明有进位,则补1
	return C;
}

法二:用普通数组来存放

代码实现:

for (int i = 0; i < s1.size(); i++) a[i] = s1[s1.size() - i - 1] - '0';
	for (int i = 0; i < s2.size(); i++) b[i] = s2[s2.size() - i - 1] - '0';//将字符串中的字符转化为数字存在整型数组中
	int maxi = max(s1.size(), s2.size());//以两个字符串中最大的长度作为遍历序列
	for (int i = 0; i < maxi; i++)
	{
		a[i] += b[i];//进行相加
		if (a[i] >= 10)
		{
			a[i] -= 10;//如果有进位的话,a[i]自减10,a[i+1]++
			a[i + 1]++;
		}
	}
	while (a[maxi]) maxi++;//只要a[maxi]不等于0,说明存在进位,则maxi++,直到a[maxi]为0

2.高精度减法

算法思想:模拟

此模板必须保证数A大于等于数B,可以提前判断一下,如果数A大于等于数B的话直接调用函数计算减A-B,否则计算B-A,但此时要注意一下输出的时候要先输出一个负号。用一个动态数组来保存相减后的数字,同时用一个变量来表示借位,初始值设置为0,最后别忘了去除前导0;

代码实现:

for (int i = s1.size() - 1; i >= 0; i--) A.push_back(s1[i] - '0');
	for (int i = s2.size() - 1; i >= 0; i--) B.push_back(s2[i] - '0');
	if (cmp(A, B))//如果数A大于等于数B
	{
		auto ans = sub(A, B);//auto会自动判断返回值类型,此时等价于vector<int>
		for (int i = ans.size()-1; i >= 0; i--) cout << ans[i];		
	}
	else
	{
		auto ans = sub(B, A);
		cout << "-";
		for (int i = ans.size() - 1; i >= 0; i--) cout << ans[i];
	}

//高精度减法
vector<int> sub(vector<int> &A, vector<int> &B)
{
	vector<int> C;
	int t=0;//表示借位,初始化为0
	for (int i = 0; i < A.size(); i++)
	{
		t = A[i] - t;
		if (i < B.size()) t -= B[i];//如果B的位数还存在的话,继续计算
		C.push_back((t + 10) % 10);//此时两种情况合二为一,t的值为负数或者为正数
		if (t >= 0) t = 0;//如果t>=0的话,表示没有借位,t为0
		else t = 1;//存在借位,t为1
	}
	while (C.size() > 1 && C.back() == 0) C.pop_back();//去除前导0
	return C;
}

注意:判断数A是否大于等于数B,以下提供两种方法

法一:用动态数组存起来,再进行判断,如果A大于等于B,返回true,否则返回false

bool cmp(vector<int> A, vector<int> B)//判断A是否大于等于B
{
	if (A.size() != B.size()) return A.size() > B.size();
	for (int i = A.size() - 1; i >= 0; i--)//从高位到低位开始依次比较
	{
		if (A[i] != B[i]) return A[i] > B[i];
	}
	return true;
}

法二:由于大数使用字符串来存放的,可以直接用字符串进行比较

代码实现:

bool cmp(string &s1,string &s2)
{
	if (s1.size() != s2.size()) return s1.size() > s2.size();
	else
	{
		if (s1 >= s2) return true;
		else return false;
	}
}

3.高精度乘法

算法思想:模拟

用一个动态数组来存放相乘后的数,变量t表示进位

代码实现:

  1. 一个大整数与一个小整数相乘
vector<int> mul(vector<int>& A, int b)
{
	vector<int> c;
	int t = 0;
	for (int i = 0; i < A.size()||t; i++)
	{
		if (i < A.size()) t += A[i] * b;
		c.push_back(t % 10);
		t /= 10;
	}
	return c;
}
  1. 两个大整数相乘
vector<int> mul(vector<int> &A,vector<int> &B)
{
    vector<int> ans(A.size()+B.size(),0);
    for(int i=0;i<A.size();i++)
    {
        for(int j=0;j<B.size();j++)
        {
            ans[i+j]+=A[i]*B[j];
        }
    }
    int t=0;
    for(int i=0;i<ans.size();i++)
    {
        t+=ans[i];
        ans[i]=t%10;
        t/=10;
    }
    while(ans.size()>1&&ans.back()==0) ans.pop_back();
    return ans;
}

4.高精度除法

算法思想:模拟

代码实现:

vector<int> div(vector<int>& A, int b, int& r)
{
	vector<int> c;
	r = 0;
	for (int i = A.size() - 1; i >= 0; i--)
	{
		r = r * 10 + A[i];
		c.push_back(r / b);
		r %= b;
	}
	reverse(c.begin(), c.end());
	while (c.size() > 1 && c.back() == 0) c.pop_back();//去除前导0
	return c;
}

	for (int i = 0; i < s.size(); i++) A.push_back(s[s.size()-i-1] - '0');
	int r;//表示余数
	auto ans = div(A, b, r);
	for (int i = ans.size() - 1; i >= 0; i--) cout << ans[i];
	cout << endl << r << endl;

二 前缀和(数组下标从1开始)

1.一维前缀和

//构造前缀和数组b[N]
for(int i=1;i<=n;i++)
{
    b[i]=b[i-1]+a[i];
}
//给定一个数组a[N],构造前缀和数组b[N],求l到r区间的元素和
b[r]=a[1]+a[2]+...+a[l-1]+a[l]+a[r]+...+a[r-1]+a[r];
b[l-1]=a[1]+a[2]+...+a[l-1]; 
b[r]-b[l-1]=a[l]+a[l+1]+...+a[r];

2.二位前缀和

/*思想:
对于一个二维矩阵a[N][N]和一个二维矩阵b[N][N],满足b[i][j]是以a[1][1]为左上角
以a[i][j]为右下角的矩阵中所有元素的和,那么就称作b[N][N]为a[N][N]的二维前缀和数组,a[N][N]为b[N][N]的二维差分数组

//给定含有n行m列的二维数组a[N][N],构造二维前缀和数组b[N][N]

*/
for(int i=1;i<=n;i++)
{
    for(int j=1;j<=m;j++)
    {
        scanf("%d",&a[i][j]);
        b[i][j]=a[i][j]+b[i-1][j]+b[i][j-1]-b[i-1][j-1];
    }
 }
 long long sum;
 sum=b[x2][y2]-b[x1-1][y2]-b[x2][y1-1]+b[x1-1][y1-1];
 printf("%d",sum); 

三 差分

1.一维差分

//给定含有n个元素的前缀和数组a[N],构造差分数组b[N]
for(int i=1;i<=n;i++)
{
    b[i]=a[i]-a[i-1];
} 
//对于一个数组a[N],构造其差分数组b[N],使得a[N]中l到r区间的所有元素加上c
//求操作后的a[N]数组
b[l]+=c;
b[r+1]-=c;
for(int i=1;i<=n;i++)
{
    a[i]=a[i-1]+b[i];//操作后的数组a[N] 
    printf("%d",a[i]);
 } 

2.二维差分

 /*给定一个二维数组a[N][N],构造其二维差分数组b[N][N],给定坐标x1,y1,x2,y2,求以(x1,y1)为左上角,(x2,y2)
 为右下角的所有元素 加或者减去一个数c,求操作后的二维数组a[N][N]
*/
/*给定一个二维数组a[N][N],构造二维差分数组b[N][N] */
for(int i=1;i<=n;i++)
{
    for(int j=1;j<=m;j++)
    {
        scanf("%d",&a[i][j]);
        b[i][j]=a[i][j]-a[i-1][j]-a[j][j-1]+a[i-1][j-1];
    }
 }
b[x1][y1]+=c;
b[x1][y2+1]-=c;
b[x2+1][y1]-=c;
b[x2+1][y2+1]+=c;
for(int i=1;i<=n;i++)
{
    for(int j=1;j<=m;j++)
    {
        a[i][j]=b[i][j]+a[i-1][j]+a[i][j-1]-a[i-1][j-1];
        printf("%d",a[i][j]);
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值