算法基础(2) | 高精度、前缀和、差分

一、高精度

1.1 高精度加法

在这里插入图片描述
在这里插入图片描述

#include <iostream>
#include <vector>

using namespace std;

const int N = 1e6 + 10;

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

int main()
{
    string a, b; //将长度太长的数字 以字符串读入
    vector<int> A, B;//大整数A 和 B 以数组形式存在
    
    cin >> a >> b;   //a = "123456"
    for (int i = a.size() - 1; i >= 0; i -- ) A.push_back(a[i] - '0'); // A = [6,5,4,3,2,1]
    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 -- ) printf("%d",C[i]);    
    
    return 0;
}
vector<int> add(vector<int> &A, vector<int> &B)
{
    vector<int> C;
    
    int t = 0;//进位
        
    if (A.size() < B.size()) return add(B, A);
    
    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(1);
    }
    
    return C;
}

1.2 高精度减法

在这里插入图片描述

#include <iostream>
#include <vector>

using namespace std;

const int N = 1010;

// A >= B?
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 -- )   // 长度相等情况下a 不等于 b的情况
        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; 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;
    }
    //去除前导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');
    
    if (cmp(A, B))
    {
        vector<int> C = sub(A, B);
        for (int i = C.size() - 1; i >= 0; i -- )   printf("%d",C[i]);
    }else
    {
        vector<int> C = sub(B, A);
        printf("-");
        
        for (int i = C.size() - 1; i >= 0; i -- )   printf("%d",C[i]);
    }
    
    return 0;
}

1.3 高精度乘法

#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 ++ )
    {
        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.size() - 1; i >= 0; i -- )  A.push_back(a[i] - '0');
    
    vector<int> C = mul(A, b);
    
    for (int i = C.size() - 1; i >= 0; i -- ) printf("%d",C[i]);
    
    
    return 0;
}

1.4 高精度除法

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>

using namespace std;

const int N = 1e6 + 10;

//A/b 商是C 余数是r
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;
    int b;
    vector<int> A;
    
    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--) printf("%d",C[i]);
    cout << endl << r << endl;
    
}

高精度汇总篇

二、前缀和

2.1 一维前缀和

核心思想:
前缀和

从1开始的好处,处理边界问题,如要求[1,10]这段和的话,之间s10即可。因为s[0] = 0;

#include <iostream>
using namespace std;

const int N = 100010;

int a[N], s[N];

int main()
{
    int n, m;
    ios::sync_with_stdio(false);
    //原理是让cin和标准输入输出不同步 提高cin读取速度
    //副作用不能用scanf了 数据规模大于等于100w建议用scanf 否则用cin即可
    
    cin >> n >> m;
    
    for (int i = 1; i <= n; i ++ ) cin >> a[i];
    for (int i = 1; i <= n; i ++ ) s[i] = s[i - 1] + a[i];
    while (m -- )
    {
        int l, r;
        cin >> l >> r;
        cout << s[r] - s[l - 1] << endl;
    }
        
    return 0;
}

2.2 二前缀和

核心思想:
在这里插入图片描述

#include <iostream>

using namespace std;

const int N = 1010;

int a[N][N];
int s[N][N];

int main()
{
    int n, m, q;
    
    cin >> n >> m >> q;
    
    //读入数组
    for (int i = 1; i <= n; i ++ )  
        for (int j = 1; j <= m; j ++ ) 
            cin >> 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;
        cin >> x1 >> y1 >> x2 >> y2;
        
        cout << s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1] << endl;  
    }
    
    return 0;
}

都是从左上到右下。

三、差分

3.1 一维差分

在这里插入图片描述
在这里插入图片描述

#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()
{
    scanf("%d%d", &n, &m);
    
    //读入数据
    for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);
    
    //进行构造b数组
    for (int i = 1; i <= n; i ++ ) insert(i, i, a[i]);
    
    // for (int i = 1; i <= n; i ++ ) cout << b[i] << ' ';
    
    while (m -- )
    {
        int l, r, c;
        scanf("%d%d%d", &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 ++ ) printf("%d ", b[i]);
    
    return 0;
}
#include <iostream>
using namespace std;

const int N = 1010;

int a[N], b[N];

int n, m;

int main()
{
    cin >> n >> m;
    
    for (int i = 1; i <= n; i ++ )  cin >> a[i];
    
    for (int i = 1; i <= n; i ++ )  b[i] = a[i] - a[i - 1];
    
    while (m -- )
    {
        int l, r, c;
        cin >> l >> r >> c;
        b[l] += c;
        b[r + 1] -= c;
    }
    
    for (int i = 1; i <= n; i ++ ) a[i] = b[i] + a[i - 1];

	for (int i = 1; i <= n; i ++ ) cout << a[i] << ' ';
    
	return 0; 
}

3.2 二维差分

在这里插入图片描述

bij是空想处理的,满足aij是b数组的前缀和,给定a数组,假想一个b数组。使得a数组是b数组的前缀和,而b数组则是a数组前缀和的逆运算。

代码:

#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()
{
    cin >> n >> m >> q;
    
    //读入数据
    for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= m; j ++ ) 
            cin >> 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]);
    
    //做q个询问
    while ( q -- )
    {
        int x1, y1, x2, y2, c;
        cin >> 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 ++ )
            a[i][j] = a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1] + b[i][j];
    
    for (int i = 1; i <= n; i ++ )
    {
       for (int j = 1; j <= m; j ++ )
       {
            cout << a[i][j] << ' ';
       }
       puts("");
    }
    return 0;
}

四、习题汇总

类型题目
二分AcWing 789. 数的范围
AcWing 790. 数的三次方根
高精度AcWing 791. 高精度加法
AcWing 792. 高精度减法
AcWing 793. 高精度乘法
AcWing 794. 高精度除法
前缀和与差分AcWing 795. 前缀和
AcWing 796. 子矩阵的和
AcWing 797. 差分
AcWing 798. 差分矩阵
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值