【基础算法(二)】

2023年9月20日

高精度计算:A+B、A-B、A*a、A/a、A/B

 1、高精度加法

// C = A + B, A >= 0, B >= 0
vector<int> add(vector<int> &A, vector<int> &B)
{
    if (A.size() < B.size()) return add(B, A);

    vector<int> C;
    int t = 0;
    for (int i = 0; i < A.size(); i ++ )
    {
        t += A[i];
        if (i < B.size()) t += B[i];
        C.push_back(t % 10);//超出10的话取余数
        t /= 10;//进位
    }
    //如果有进位
    if (t) C.push_back(t);
    return C;
}

#include <iostream>
#include <vector>

using namespace std;

vector<int> add(vector<int> &A,vector<int> &B)
{
    if(A.size()<B.size())   return add(B,A);
    
    vector<int> C;
    int t= 0;//表示进位
    for(int i=0;i <A.size();i++)
    {
        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(){
    string a,b;
    vector<int> A,B;
    cin>>a>>b;
    for(int i = a.size()-1;i>=0;i--) A.push_back(a[i]-'0');
    for(int i = b.size()-1;i>=0;i--) B.push_back(b[i]-'0');
    
    auto C=add(A,B);
    
    for(int i=C.size()-1;i>=0;i--) cout<<C[i];
    cout<<endl;
    
    return 0;
}


2.高精度减法

// C = A - B, 满足A >= B, A >= 0, B >= 0
vector<int> sub(vector<int> &A, vector<int> &B)
{
    //需要保证A>=B,B的位数有可能比A少
    vector<int> C;
    for (int i = 0, t = 0; i < A.size(); i ++ )
    {
        //每一位都是A[i]-B[i]-t
        t = A[i] - t;

        //如果B有这一位
        if (i < B.size()) t -= B[i];
        //将两种情况合起来
        C.push_back((t + 10) % 10);
        if (t < 0) t = 1;
        else t = 0;
    }
    //去掉了高位多余的0
    while (C.size() > 1 && C.back() == 0) C.pop_back();
    return C;
}

#include <iostream>
#include <vector>

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;
    //判读A是否大于等于B
}


vector<int> sub(vector<int> &A,vector<int> &B)
{
    
    vector<int> C;
    int t= 0;//表示借位
    for(int i=0,t=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();
    return C;
}

int main(){
    string a,b;
    vector<int> A,B;
    cin>>a>>b;
    for(int i = a.size()-1;i>=0;i--) A.push_back(a[i]-'0');
    for(int i = b.size()-1;i>=0;i--) B.push_back(b[i]-'0');
    
    vector<int> C;
    if(cmp(A,B)) C=sub(A,B);
    else    C=sub(B,A),cout<<'-';
    
    for(int i=C.size()-1;i>=0;i--) cout<<C[i];
    cout<<endl;
    
    return 0;
}

3、高精度乘法

// C = A * b, A >= 0, b >= 0
vector<int> mul(vector<int> &A, int b)
{
    vector<int> C;

    int t = 0;//进位
    //两个判断条件,一个是A还有位数,一个是进位还没有处理完
    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;
}

#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()
{
    string a;
    int b;

    cin >> a >> b;

    vector<int> A;
    for (int i = a.size() - 1; i >= 0; i -- ) A.push_back(a[i] - '0');

    auto C = mul(A, b);

    for (int i = C.size() - 1; i >= 0; i -- ) printf("%d", C[i]);

    return 0;
}

4、高精度除法

// A / b = C ... r, A >= 0, b > 0
vector<int> div(vector<int> &A, int b, int &r)
{
    //注意这里函数传入的参数是 int &r,否则不能改变外部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());
    
    //处理前导0
    while (C.size() > 1 && C.back() == 0) C.pop_back();
    return C;
}

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

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();
    return C;
}

int main()
{
    string a;
    vector<int> A;

    int B;
    cin >> a >> B;
    for (int i = a.size() - 1; i >= 0; i -- ) A.push_back(a[i] - '0');

    int r;
    auto C = div(A, B, r);

    for (int i = C.size() - 1; i >= 0; i -- ) cout << C[i];

    cout << endl << r << endl;

    return 0;
}


5、前缀和

参考链接

【学习总结】一、二维前缀和 && 一、二维差分_吹往北方的风的博客-优快云博客

//一维前缀和
S[i] = a[1] + a[2] + ... a[i]
a[l] + ... + a[r] = S[r] - S[l - 1]

//二维前缀和——子矩阵的和
S[i, j] = 第i行j列格子左上部分所有元素的和
//前缀和矩阵的求法
S[i,j] = s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j]

//以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵的和为:
S[x2, y2] - S[x1 - 1, y2] - S[x2, y1 - 1] + S[x1 - 1, y1 - 1]
#include <iostream>

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]); // 区间和的计算
    }

    return 0;
}

#include <iostream>
using namespace std;

const int N =1010;
int n,m,q;
int 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("%d",&s[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]+s[i][j];
    
    while(q--){
        int x1,x2,y1,y2;
        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
        printf("%d\n",s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1]);
    }
    
    
}

6、差分

前缀和是差分的逆运算
//a1,a2,a3....an前缀和数组(原数组)
//b1,b2,b3....bn差分数组    b1=a1,b2=a2-a1,b3=a3-a2....
假想一个b数组,使得a数组是b数组的前缀和
如果需要求原数组a,只需要对b数组求前缀和

构造差分数组时,看作[1,1]+a1、[2,2]+a2、[3,3]+a3........

//一维差分
给a数组中区间[l, r]中的每个数加上c:B[l] += c, B[r + 1] -= c

//二维差分
//aij是前缀和数组(原数组),表示左上角所有bij的和
给以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵中的所有元素加上c:
S[x1, y1] += c, S[x2 + 1, y1] -= c, S[x1, y2 + 1] -= c, S[x2 + 1, y2 + 1] += c

(1)一维差分

#include <iostream>
using namespace std;

const int N =100010;
int n,m;
int a[N],b[N];

void insert(int l,int r,int c){
    b[l]+=c;
    b[r+1]-=c;
}

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++)   insert(i,i,a[i]);
    
    while(m--){
        int l,r,c;
        //插入操作 
        scanf("%d%d%d",&l,&r,&c);
        insert(l,r,c);
    }
    //求前缀和,即求a数组
    for(int i=1;i<=n;i++)   b[i]=b[i-1]+b[i];
    
    for(int i=1;i<=n;i++)   printf("%d ",b[i]);
    return 0;
}

(2)二维差分

#include<iostream>

using namespace std;

const int N =1010;
int a[N][N],b[N][N];
int n,m,q;
void insert(int x1,int y1,int x2,int y2,int c)
{
    b[x1][y1]+=c;
    b[x2+1][y1]-=c;
    b[x1][y2+1]-=c;
    b[x2+1][y2+1]+=c;
}

int main(){
    scanf("%d%d%d",&n,&m,&q);
    //输入初始矩阵
    for(int i=1;i<=n;i++)
        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++)
            insert(i,j,i,j,a[i][j]);
            
    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++)   
            b[i][j]=b[i-1][j]+b[i][j-1]-b[i-1][j-1]+b[i][j];
            
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)   printf("%d ",b[i][j]);
        printf("\n");
        
    }
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值