高精度
存储:大整数在C++里用数组存储,存储时应当高位在前,即在数组第一位存个位,因为若出现进位,则需要在数组末尾增添的情况比较方便。
有四种情况,A+B,A-B,A*a,A/a。现分别讨论:
情况一:A+B,整数规模在10^6之内。算法思想就是模拟人工计算过程。即各个位数相加后进行结果处理,若出现进位则在下一位的处理加上进位进行
#include<bits/stdc++.h>
using namespace std;
vector<int> add(vector<int> &a,vector<int> &b){
int t=0; //用来保存进位
vector<int >c;
for(int i=0;i<a.size()||i<b.size();i++){
if(i<a.size()) t+=a[i];
if(i<b.size()) t+=b[i];
c.push_back(t%10);//若每次将余数存到当前位置
t/=10;//出现进位则将进位加到下一数位的加法中
}
if(t) c.push_back(1);
return c;
}
int main(){
string a,b;
vector<int> va,vb;
cin>>a>>b;
for(int i=a.length()-1;i>=0;i--) va.push_back(a[i]-'0'); //将加数的个位移动到第一位
for(int i=b.length()-1;i>=0;i--) vb.push_back(b[i]-'0');
auto vc=add(va,vb);//auto变量编译器自己判定变量类型
for(int i=vc.size()-1;i>=0;i--) printf("%d",vc[i]);//输出时从高位到地位进行输出
}
情况二:A-B,整数规模在10^6之内。
每次相对应的数位进行相减,若够减,直接减,若不够减,则需借位。计算相对应的数位是记得减去相对应的数位。在进行减法之前,可以先判断谁大,用大的数减去小的数之后,根据实际输入判断是否出现加负号的情况。
#include<bits/stdc++.h>
using namespace std;
bool cmp(vector<int>& A,vector<int> &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;
}
vector<int> sub(vector<int>& A,vector<int> &B){
int t=0; //用来保存借位
vector<int>c;
for(int i=0;i<A.size();i++){
t=A[i]-t;
if(i<B.size()) t-=B[i];
C.push_back((t+10)%10);//将两种情况进行综合处理
if(t<0) t=1;
else t=0;
}
while(c.size()>1&&c.back()==0) c.pop_back();//若出现相减之后只有高位出现0的情况,将后面的
// 0弹出
return c;
}
int main(){
string a,b;
vector<int> A,B;
cin>>a>>b;
for(int i=a.length()-1;i>=0;i--) A.push_back(a[i]-'0'); //将需要处理的数据的个位移动到
//第一位
for(int i=b.length()-1;i>=0;i--) B.push_back(b[i]-'0');
if(cmp(A,B)){
auto c=sub(A,B);
for(int i=c.size()-1;i>=0;i--) printf("%d",c[i]);//输出时从高位到地位进行输出
}
return 0;
}
情况三:A*a,A的长度<10^6,a<10^5
高精度整数*低精度整数。手算模拟情况可以得知,每次是将A的大数分别乘上a,当前数位保留的是乘法结果对10取余,进位的大小则是除以10的结果。
#include<bits/stdc++.h>
using namespace std;
vector<int> mul(vector<int>&A,int &b){
int t=0; //用来保存进位
vector<int> c;
for(int i=0;i<A.size() || t;i++){//在A没循环完或者进位t还没处理完。
if(i<A.size()) t+=A[i]*b;
c.push_back(t%10);//若每次将余数存到当前位置
t/=10;//出现进位则将进位加到下一数位的运算中
}
return c;
}
int main(){
string a;
int b;
vector<int> A;
cin>>a>>b;
for(int i=a.length()-1;i>=0;i--) A.push_back(a[i]-'0'); //将数的个位移动到第一位
auto c=mul(A,b);//auto变量编译器自己判定变量类型
for(int i=c.size()-1;i>=0;i--) printf("%d",c[i]);//输出时从高位到地位进行输出
}
情况四:A/a
高精度整数/低精度整数。
#include<bits/stdc++.h>
using namespace std;
vector<int> mul(vector<int>&A,int &b,int &r){
r=0; //用来保存余数
vector<int> c;
for(int i=A.size()-1;i>=0;i--){//在A没循环完或者进位t还没处理完。
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的情况,将后面的
// 0弹出
return c;
}
int main(){
string a;
int b;
vector<int> A;
cin>>a>>b;
for(int i=a.length()-1;i>=0;i--) A.push_back(a[i]-'0'); //将数的个位移动到第一位
auto c=div(A,b,r);//auto变量编译器自己判定变量类型
for(int i=c.size()-1;i>=0;i--) printf("%d",c[i]);//输出时从高位到地位进行输出
cout<<endl<<r<<endl;
return 0;
}
前缀和
前缀和Si=a1+a2+a3+...an
如何求Si以及作用。Si是通过前i-1项的前缀和加上第i个值。作用是能够快速的求出任意一段区间Sr-Sl-1的和。注意下标从1开始,可以省去边界判断的问题。
一维前缀和
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int n,m;
int a[N],s[N];
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];
while(m--){
int l,r;
scanf("%d%d",&l,&r);
printf("%d\n",s[r]-s[l-1]);
}
}
二维前缀和
Sij表示左上角部分的前缀和
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1010;
int n,m,q;
ll a[N][N],s[N][N];
int main(){
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%lld",&a[i][j]);
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j];
}
}
while(q--){
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
printf("%lld\n",s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1]);
}
}
差分
已知一个数组a,构造出数组b,使得ai=b1+b2+b3+...bi
一维差分
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int a[N],b[N];//A是原数组,B是差分数组
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) b[i]=a[i]-a[i-1];
while(m--){
int l,r,c;
scanf("%d%d%d",&l,&r,&c);
b[l]+=c;
b[r+1]-=c;
}
for(int i=1;i<=n;i++){
a[i]=a[i-1]+b[i];
printf("%d ",a[i]);
}
}
差分矩阵(二维差分)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1010;
ll a[N][N],b[N][N];
void Insert(int x1,int y1,int x2,int y2,ll c){
b[x1][y1]+=c;
b[x2+1][y1]-=c;
b[x1][y2+1]-=c;
b[x2+1][y2+1]+=c;
}
int main(){
int n,m,q;
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%lld",&a[i][j]);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
Insert(i,j,i,j,a[i][j]);
while(q--){
int x1,y1,x2,y2;
ll c;
scanf("%d%d%d%d%lld",&x1,&y1,&x2,&y2,&c);
Insert(x1,y1,x2,y2,c);//起初将a数组看成空的,执行插入操作
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
b[i][j]+=b[i-1][j]+b[i][j-1]-b[i-1][j-1];//原数组即差分数组的前缀和
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
printf("%lld ",b[i][j]);
cout<<endl;
}
}