一 高精度
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表示进位
代码实现:
- 一个大整数与一个小整数相乘
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;
}
- 两个大整数相乘
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]);
}
}