本系列所有题目均为Acwing课的内容,发表博客既是为了学习总结,加深自己的印象,同时也是为了以后回过头来看时,不会感叹虚度光阴罢了,因此如果出现错误,欢迎大家能够指出错误,我会认真改正的。同时也希望文章能够让你有所收获,与君共勉!
今天学习大数之间的加减乘除,我们知道通常整型变量的存储范围为-2147483648~2147483647
,当两个数值的操作结果大于这个数时就会溢出。因此为了解决这个问题,我们可以使用vector(数组)的方式去模拟四则运算的计算过程,将结果存储在容器内,从而避免溢出的风险。
高精度加法
代码实现
vector<int> add(vector<int> &A,vector<int> &B){ // A>0,B>0
if(A.size() < B.size()) return add(B,A); // A一定是长度最长的数字.
vector<int> C;
int t = 0; // 当前位上的数
for(int i=0; i < A.size() ; ++i)}{
t += A[i]; // A的对应位加上一位的余数
if(i < B.size()) t += B[i]; // 如果B还存在,就取B对应位进行计算
C.push_back(t%10); // 结果对应位上的数
t / = 10; // 取其余数作为进位数
}
if(t) C.push_back(t); // 如果最后一位相加还有余数就继续存储
return C;
}
高精度减法
代码实现
voctor<int> sub(vector<int>&A,vector<int> &B){ // 注意:一定是A更长且A>= B,A>0,B>0
vector<int> C;
int t = 0;
for(int i=0; i < C.size() ; ++i){
t = A[i] - t; // 减去上一位所借的数
if(i<B.size()) t -= B[i] ; // 如果B还存在
C.push_bakc((t + 10) % 10); //+10是为了防止是负数
if(t < 0) t = 1; // 要向下一位借1
else t = 0; // 对下一位没影响
}
while(C.size() > 1 && C.back() == 0) C.pop_back();
// 如果最后一位刚好位0,则删除最后一位。且不会小于0。因为A >= B
return C;
}
高精度乘法
代码实现
voctor<int> mul(vector<int>&A,int b){ // 注意:这是高精度乘低精度的,即A用vector装,b用int装,且A>0,b>0
vector<int> C;
int t = 0;
for(int i=0 ; i<A.size() && t ; ++i){ // &&t是为了最后一位相乘的结果是多位可以在这个循环里就给他挨个存储到C里面
if(A.size() > i) t += A[i] * b; // 如果A没有乘尽,依然是对位相乘
C.push_back(t%10); // 将该位上的值存在C中
t/=10; // 舍去个位,取得进位
}
while(A.size()> 1 && C.back() == 0) C.pop_back();
return C;
}
高精度除法
代码实现
vector<int> div(vector<int> &A,int b) { // 依然是高精度除低精度的且A.0,b>0
vecotr<int> C;
int t = 0;
for(int i=A>size()-1 ; i >= 0 ; --i){ // 模拟除法都是先运算高位的
t = t*10 + A[i]; // 下一位不都是上一位的余数*10在加上这一位嘛,余数最多也才到9
C.push_back(t/b) // 当第一位比b小时,就会取0,反转过来就会产生后置0,因此后面也要去0
t%=b;
}
reverse(C.begin(),C.end());
while(C.size() > 1 && C.back() == 0) C.pop_back();
return C;
}
啊,难受,中午一点开始弄到一半被叫去实习,磨了一下午的锤子,终于磨完了,本以为能休息会,没想到又要弄车床,时间就这样流逝了,我美好的星期五啊!!!
好了,所以晚上回来特地多写一些模板,多复习一点吧。
前缀和与差分
由于本人还没有学习Latex的数学公式,而且我感觉在markdown上面直接敲推导公式数学符号也太难看了,所以各位就请自己去寻找更详细的内容吧,
这里主要来说一下前缀和和差分能用来干什么。
我们很容易的知道,在一维数组a
,b
中,当我们想要知道数组a
中一段连续区间[i,j]
的和时,我们需要去遍历这段区间,时间复杂度为O(n)
,这时我们可以使用一维前缀和,它可以帮我们用O(1)
的时间复杂度求解出来。表达式如下:
当我们需要对区间[i,j]
中的每一个数字都进行加减r操作时,时间复杂度为O(n)
,我们可以使用一维差分,时间复杂度为O(1)
。以加法为例,表达式如下:
注意更改完后要对差分数组求一维前缀和才会得到对原数组进行操作后的新数组。
二维数组的情况类似,只不过二维前缀和是一个矩阵内所有数字的和,假设二维数组a
,b
,区间[x_1,y_1]~[x_2,y_2]
的二维前缀和的公式如下:
构造前缀和的公式为:
\[b[i][j] = a[i-1][j] + a[i][j-1] + a[i][j] - a[i-1][j-1] \]二维差分也与一维差分类似,功能上是对一个矩阵内的元素都加减r
,以加法为例,对区间[x_1,y_1]~[x_2][y_2]
其公式为:
同时也要注意对二维差分数组求二维前缀和才是更改后的新数组。
写完都11点了,离谱~~~~!