目录
前言: 大体内容from acwing yxc。
一、高精度
1.高精度加法
思路没什么好说的吧,t 代表进位,t%10代表进过之后剩下的,t/10代表向下一位进的数。
#include<iostream>
#include<vector>
using namespace std;
vector<int> add(vector<int>& A, vector<int>& B)
{
vector<int> C;
int t = 0;
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(t);
return C;
}
int main(void)
{
string a, b;
cin >> a >> b;
vector<int> A, B;
for (int i = a.size() - 1; i >= 0; i--) A.push_back(a[i] - 48);
for (int i = b.size() - 1; i >= 0; i--) B.push_back(b[i] - 48);
auto C = add(A, B);
for (int i = C.size()-1;i >= 0; i--)
{
cout << C[i] << "";
}
return 0;
}
2.高精度减法
实际上和加法差不多,不过可以注意一下t作为进位的用法。t此时只有0和1两种取值。
//这里填你的代码^^
#include<vector>
#include<iostream>
#include<cstring>
using namespace std;
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;
}
vector<int> sub(vector<int>&A,vector<int>&B)
{
vector<int> C;
for(int i=0,t=0;i<A.size();i++)
{
t=A[i]-t;
if(i<B.size()) t-=B[i];//可能这个位置 B里已经没有元素了
C.push_back((t+10)%10);
if(t<0) t=1;
else t=0;
}
while(C.size()>1&&C.back()==0) C.pop_back();
return C;
}
int main()
{
string a,b;
cin>>a>>b;
vector<int> A,B;
for(int i=a.size()-1;i>=0;i--) A.push_back(a[i]-48);
for(int i=b.size()-1;i>=0;i--) B.push_back(b[i]-48);
if(cmp(A,B))
{
auto C=sub(A,B);
for(int i=C.size()-1;i>=0;i--) cout<<C[i];
}
else
{
auto C=sub(B,A);
cout<<"-";
for(int i=C.size()-1;i>=0;i--) cout<<C[i];
}
}
//注意代码要放在两组三个点之间,才可以正确显示代码高亮哦~
作者:yankai
链接:https://www.acwing.com/activity/content/code/content/3345876/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
3.高精度乘法
有别于我们自己的乘法过程,这里我们将b看做是一个整体,进位方式和加法差不多。
在for循环中采用了一个很巧妙的方式。因为判断循环的条件只有i<A。size(),所以当我们出循环的时候,如果进位t不为0,我们就需要在最后面加上这个进位。但如下方法在循环内就搞定了。
还有一个注意点,如果我们乘一个0,那么返回的C就是一个全是0的数组,显然是无意义的。有没有别的高位数为0的情况没仔细想,但是根据这个特例,我们知道最后要对C做一个和减法差不多的操作,把在高位的0去掉。
#include<iostream>
#include<vector>
using namespace std;
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;
}
while(C.size()>1&&C.back()==0) C.pop_back();
return C;
}
int main(void)
{
string a;
int b;
cin>>a>>b;
vector<int> A;
for(int i=a.size()-1;i>=0;i--) A.push_back(a[i]-48);
auto C=mul(A,b);
for(int i=C.size()-1;i>=0;i--) cout<<C[i];
}
4.高精度除法
模拟一下我们正常做除法的过程,首先被除数第一位除以除数,除数给商,余数进行下一步运算。在下一步中,我们需要把被除数的下一位直接拿下来,对应的数学运算就是上一步的余数r*10+A[I]。
至此循环内的过程就明白了,观察边界,当我们处理完被除数最后一位的时候循环停止。
因此具体实现过程如下:
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
#include<algorithm>
vector<int> div(vector<int>&A,int b,int& r)//注意是用引用的方式传入r
{
r=0; vector<int> C;
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());//按规定,我们还是把C翻转,这个函数在algorithm库中
while(C.size()>1&&C.back()==0) C.pop_back();//在图中例子中,我们发现要去前导0
return C;
}
int main()
{
string a;
int b;
cin>>a>>b;
vector<int> A;
for(int i=a.size()-1;i>=0;i--) A.push_back(a[i]-48);
int r;
auto C=div(A,b,r);
for(int i=C.size()-1;i>=0;i--) cout<<C[i];
cout<<endl<<r;
}
二、前缀和、差分
1.一维前缀和
前缀和,一串数的前n项和。特别地令这串数的下标从1开始,我们存储S[0]=0
前缀和的作用是可以方便计算出数组一段区间子序列的和。譬如a[l]+a[l+1]······a[r]=S[r]-S[l-1]。
要生成这个S数组也很简单,利用循环,令S[i]=S[i-1]+a[i]。
2.二维前缀和
实际上S[i][j]是包括a[i][j]的左上角的所有元素的和。
作用是可以求一个子矩阵的和。
计算方法有点容斥原理的思想。左下为求和方法,右上是循环时赋值的公式。
//这里填你的代码^^
#include<iostream>
using namespace std;
int n,m,q;
const int N=1005;
int a[N][N],s[N][N];
int main()
{
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n;i++)//注意从1开始!!!!
for(int j=1;j<=m;j++)
scanf("%d",&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];//注意别顾着想s那一堆忘了a
while(q--)
{
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
cout<<s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1]<<endl;
}
return 0;
}
//注意代码要放在两组三个点之间,才可以正确显示代码高亮哦~
作者:yankai
链接:https://www.acwing.com/activity/content/code/content/3360202/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
3.一维差分
定义:可以理解为前缀和的逆运算,对于一个数组a[i],我们构造一个b[i]使得a是b的前缀和。
构造方式如图左下角。差分的作用是快速的向a数组中[l,r]里所有元素同时加上一个值。对于这个操作,我们只需要让b[l]++,b[r+1]--;(可以留意一下对差分数组里l位置做的操作,会影响根据这个差分数组求出来的原数组,l及其之后所有位置的元素)。
有了上面的基础,我们发现其实不需要去绞劲脑汁想一个差分数组是如何构造的。我们只需要将a,b数组同时全部看成0,然后向a数组中一个个赋值,这个赋值操作实际上就是向让[i,i]区间里的数加上元素值(实际上就一个数ww),所以只需要b[i]+a[i],b[i+1]-a[i]就好了。这个思想在二维差分中体现更加明显。
//这里填你的代码^^
#include<iostream>
using namespace std;
const int N =100010;
int a[N] ,b[N];
int n,m;
void insert(int l,int r,int c )
{
b[l]+=c;
b[r+1]-=c;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) insert(i,i,a[i]);
while(m--)
{
int l,r,c;
cin>>l>>r>>c;
insert(l,r,c);
}
for(int i=1;i<=n;i++) b[i]+=b[i-1];
for(int i=1;i<=n;i++) cout<<b[i]<<" ";
return 0;
}
//注意代码要放在两组三个点之间,才可以正确显示代码高亮哦~
作者:yankai
链接:https://www.acwing.com/activity/content/code/content/3361185/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
4.二维差分
借助差分以及二维前缀和的定义,我们可以想象二维差分就是b[i][j]左上的所有元素之和等于a[i][j].
此时我们如果要对a的一个子矩阵,x1,y1,x2,y2这里面的所有元素加上某个值。方法如图。
向构造差分数组时也就是向a数组中x1,y1,x1,y1这里面所有数加一
这里为了防止空间溢出,所以不开一个b数组作为差分数组了,直接用a存储。
//这里填你的代码^^
#include<iostream>
using namespace std;
const int N =10010;
int n,m,q;
int a[N][N];
void insert(int x1,int y1,int x2,int y2,int c)
{
a[x1][y1]+=c;
a[x2+1][y1]-=c;
a[x1][y2+1]-=c;
a[x2+1][y2+1]+=c;
}
int main()
{
cin>>n>>m>>q;
int x;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
x=0,cin>>x,insert(i,j,i,j,x);
while(q--)
{
int x1,y1,x2,y2,c;
cin>>x1>>y1>>x2>>y2>>c;
insert(x1,y1,x2,y2,c);
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1];
cout<<a[i][j]<<" ";
}
cout<<endl;
}
return 0;
}
//注意代码要放在两组三个点之间,才可以正确显示代码高亮哦~
作者:yankai
链接:https://www.acwing.com/activity/content/code/content/3362034/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。