• 代码模板2---基础算法(高精度/前缀和/差分)


    一、高精度

    1.高精度加法

    string读入到vector中(注意前面存储的是较低位,是为了方便vector在back进行加一位)

    1. // C = A + B, A >= 0, B >= 0
    2. vector<int> add(vector<int> &A, vector<int> &B)
    3. {
    4. if (A.size() < B.size()) return add(B, A);//让下面的默认A是较大者
    5. vector<int> C;
    6. int t = 0;
    7. for (int i = 0; i < A.size(); i ++ )
    8. {
    9. t += A[i];
    10. if (i < B.size()) t += B[i];
    11. C.push_back(t % 10);
    12. t /= 10;//是否需要进位在此体现
    13. }
    14. if (t) C.push_back(t);//看最后是否会有进位
    15. return C;
    16. }

    2.高精度减法

    整体的思路: ①若A>=B,直接计算A-B ②若A

    注:①(t+10)%10 是为了当t<0的时候(是需要借一位的)当t>0的时候%10不变!---统一解 

           ②最后一步勿忘记去除高位0(减法会将高位消成0)

    1. // C = A - B, 满足A >= B, A >= 0, B >= 0
    2. vector<int> sub(vector<int> &A, vector<int> &B)
    3. {
    4. vector<int> C;
    5. for (int i = 0, t = 0; i < A.size(); i ++ )
    6. {
    7. t = A[i] - t; //先处理是否有借位
    8. if (i < B.size()) t -= B[i];
    9. C.push_back((t + 10) % 10);
    10. if (t < 0) t = 1; //当t<0,表示需要借位,t=1
    11. else t = 0;
    12. }
    13. while (C.size() > 1 && C.back() == 0) C.pop_back();//去除高位0!!!
    14. return C;
    15. }

    加法和减法统一是:①先处理t(让t对下一位产生影响)

                                    ②如果没超过b的size,才进行操作add or sub

                                    ③然后进行res的push_back

                                    ④最后进行t的改变 

    3.高精度乘法

    几个细节见注释(循环条件t+中间处理步骤+去除前导零)

    1. // C = A * b, A >= 0, b >= 0
    2. vector<int> mul(vector<int> &A, int b)
    3. {
    4. vector<int> C;
    5. int t = 0;
    6. for (int i = 0; i < A.size() || t; i ++ )//注意t不为0的时候,也需要进行循环!
    7. {
    8. if (i < A.size()) t += A[i] * b;
    9. C.push_back(t % 10); //将res进行push_back
    10. t /= 10; //最后更新t
    11. }
    12. while (C.size() > 1 && C.back() == 0) C.pop_back();//去除前导零
    13. return C;
    14. }

    4.高精度除法

    1. // A / b = C ... r, A >= 0, b > 0
    2. vector<int> div(vector<int> &A, int b, int &r)//余数用引用返回
    3. {
    4. vector<int> C;
    5. r = 0;
    6. for (int i = A.size() - 1; i >= 0; i -- )//从末尾(即较高的数位开始处理)
    7. {
    8. r = r * 10 + A[i];//每处理下一个顺位的时候,需要先乘上10
    9. C.push_back(r / b);//res进行push_back整除后的值
    10. r %= b; //更新r(余数),下一轮需要重复第一行
    11. }
    12. reverse(C.begin(), C.end());//数的高位在vec的低位
    13. while (C.size() > 1 && C.back() == 0) C.pop_back();//去除前导0
    14. return C;
    15. }
    16. //高精度除以低精度

    一般是从最高位开始处理的,%余下的数乘10+下一位的数字进行下一步操作 

    二、前缀和、差分

    1.前缀和

    注意:a0=0包括二维数组也是从零开始,这样公式就可以统一了,al+...+ar=Sr-S(l-1)

    当left=1,right=x的时候,利用S[x]-S[1-1]=S[x]-S[0]=S[x]-0统一公式.

            ①一维数组的前缀和

    公式:

            S[i] = a[1] + a[2] + ... a[i]
            a[l] + ... + a[r] = S[r] - S[l - 1]

    1. int l , r;
    2. cin >> l >> r;
    3. cout << S[r] - S[l - 1];

            ②二维数组的前缀和

    公式:

    S[i, j] = 第i行j列格子左上部分所有元素的和
    ①以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵的和为:
            S[x2, y2] - S[x1 - 1, y2] - S[x2, y1 - 1] + S[x1 - 1, y1 - 1]

         tips:同样的真正的下标从1开始,这样统一公式,上述公式即可变成(x2,y2)到(x1-1,y1-1)

    ②初始化S矩阵:
            s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j]

    1. int a[N][N] , S[N][N]; // N由实际需要确定其值
    2. for(int i = 1; i <= n; i ++) //先定义数组元素
    3. for(int j = 1; j <= m; j ++){
    4. scanf("%d" , &a[i][j]);
    5. }
    6. for(int i = 1; i <= n; i ++) //求前缀和
    7. for(int j = 1; j <= m; j ++){
    8. S[i][j] = S[i - 1][j] + S[i][j - 1] - S[i - 1][j - 1] + a[i][j];
    9. }
    1. int S[N][N]; // N由实际需要确定其值
    2. int x1 , x2 , y1 , y2;
    3. scanf("%d%d%d%d",&x1 , &y1 , &x2 , &y2);
    4. //计算子矩阵的和
    5. printf("%d\n" , S[x2][y2] - S[x2][y1-1] - S[x1 - 1][y2] + S[x1-1][y1-1]);

    2.差分

     ①一维差分

    板子:

            给区间[l, r]中的每个数加上c:B[l] += c, B[r + 1] -= c

    1. void insert(int l,int r,int c)
    2. {
    3. b[l]+=c;
    4. b[r+1]-=c;
    5. }
    6. int main()
    7. {
    8. ios::sync_with_stdio(false);
    9. cin>>n>>m;
    10. for(int i=1;i<=n;i++)
    11. cin>>q[i];
    12. for(int i=1;i<=n;i++)
    13. insert(i,i,q[i]);//构造差分矩阵
    14. while(m--)
    15. {
    16. int l,r,c;
    17. cin>>l>>r>>c;
    18. insert(l,r,c);
    19. }//修改差分矩阵
    20. for(int i=1;i<=n;i++)
    21. q[i]=q[i-1]+b[i];//求前缀和
    22. for(int i=1;i<=n;i++)
    23. cout<" ";
    24. return 0;
    25. }

    ②二维差分

    板子:

    给以(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. void insert(int x1,int y1,int x2,int y2,int c)
    2. {
    3. b[x1][y1]+=c;
    4. b[x1][y2+1]-=c;
    5. b[x2+1][y1]-=c;
    6. b[x2+1][y2+1]+=c;
    7. }
    8. int main()
    9. {
    10. ios::sync_with_stdio(false);
    11. cin>>n>>m>>q;
    12. for(int i=1;i<=n;i++)
    13. for(int j=1;j<=m;j++)
    14. cin>>a[i][j];
    15. for(int i=1;i<=n;i++)
    16. for(int j=1;j<=m;j++)
    17. insert(i,j,i,j,a[i][j]);//构造差分矩阵b
    18. while(q--)
    19. {
    20. int x1,y1,x2,y2,c;
    21. cin>>x1>>y1>>x2>>y2>>c;
    22. insert(x1,y1,x2,y2,c);
    23. }
    24. for(int i=1;i<=n;i++)
    25. for(int j=1;j<=m;j++)
    26. a[i][j]=a[i-1][j]+a[i][j-1]-a[i-1][j-1]+b[i][j];//求二维前缀和
    27. for(int i=1;i<=n;i++)
    28. {
    29. for(int j=1;j<=m;j++)
    30. cout<" ";
    31. cout<
    32. }
    33. return 0;
    34. }

    补充:     有关insert构造差分矩阵的含义

  • 相关阅读:
    Android Native 内存泄漏系统化解决方案
    ABB机器人如何在自动运行中修改目标点位的坐标数据?
    (附源码)spring boot投稿和稿件处理系统 毕业设计 201458
    golang从0到1实战系统四十:处理表单的输入
    springboot个性化课程推荐系统毕业设计源码131805
    【网络篇】第八篇——多进程版的TCP网络程序
    DDD领域驱动设计-聚合
    node.js - 路由、中间件、mysql
    被迫开始学习Typescript —— vue3的 props 与 interface
    javaweb+MySQL阶段总结
  • 原文地址:https://blog.csdn.net/zjjaibc/article/details/127561823