3.22 23 acwing算法基础课 第一章 高精度和前缀和差分算法

一、

791. 高精度加法

给定两个正整数(不含前导 00),计算它们的和。

输入格式

共两行,每行包含一个整数。

输出格式

共一行,包含所求的和。

数据范围

1≤整数长度≤1000001≤整数长度≤100000

输入样例:

12
23

输出样例:

35

思路:

使用t来记录进位,考虑a,b的数位大小,我的思路为a>b;还有几个注意点,使用string输入,并将每一位其转化为int存在a,b中,主要以个位到首位这样存储,也是从个位到首位这样加。

vector<int> add(vector<int>&a,vector<int>&b)
{
    if(a.size()<b.size())
    {
        return add(b,a);
    }
    int t=0;
    vector<int>c;
    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;
}
int main()
{
    vector<int> a,b;
    string 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];
    }
    return 0;
}

---------------------------------------------------------------------------------------------------------------------------------

二、高精度减法

792. 高精度减法

给定两个正整数(不含前导 00),计算它们的差,计算结果可能为负数。

输入格式

共两行,每行包含一个整数。

输出格式

共一行,包含所求的差。

数据范围

1≤整数长度≤1051≤整数长度≤105

输入样例:

32
11

输出样例:

21

 思路:

1.若a>b,则直接调用a-b;若a<b,则调用b-a取负号;

2.使用t记录进位

3.编写比较a,b数组函数cmp

4.记得弹出头位的0

5.注意当i>=b.size()时,不减去b[i],因为已经超格

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> jian(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=t-b[i];
        c.push_back((t+10)%10);
        t=t>=0?0:1;
    }
    while(c.size()>1&&c.back()==0)c.pop_back();
    return c;
}
int main()
{
    vector<int> a,b;
    string 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))
    {
        auto c=jian(a,b);
        for(int i=c.size()-1;i>=0;i--)
    {
        cout<<c[i];
    }
    }
    else
    {
        auto c=jian(b,a);
        cout<<"-";
        for(int i=c.size()-1;i>=0;i--)
        {
            cout<<c[i];
        }
    }
    return 0;
}

 --------------------------------------------------------------------------------------------------------------------------------

三、高精度乘法

793. 高精度乘法

给定两个非负整数(不含前导 00) AA 和 BB,请你计算 A×BA×B 的值。

输入格式

共两行,第一行包含整数 AA,第二行包含整数 BB。

输出格式

共一行,包含 A×BA×B 的值。

数据范围

1≤A的长度≤1000001≤A的长度≤100000,
0≤B≤100000≤B≤10000

输入样例:

2
3

输出样例:

6

思路:

1.让大数A每个数位成小数值b,用t记录进了多少位,在下一位乘的时候加上即可

2.因为遍历完a.size()时,t的结果还有进位没有加,加上即可;

vector<int> cheng(vector<int> &a,int b)
{
    vector<int> c;
    if(b==0)
    {
        c.push_back(0);
        return c;
    }
    int t=0;
    for(int i=0;i<a.size();i++)
    {
        t=t+a[i]*b;
        c.push_back(t%10);
        t=t/10;
    }
    while(t!=0)
    {
        c.push_back(t%10);
        t/=10;
    }
    return c;
}
int main()
{
    vector<int>A;
    string a;
    int b;
    cin>>a>>b;
    for(int i=a.size()-1;i>=0;i--)
    {
        A.push_back(a[i]-'0');
    }
    auto c=cheng(A,b);
    for(int i=c.size()-1;i>=0;i--)
    {
        cout<<c[i];
    }
    return 0;
}

---------------------------------------------------------------------------------------------------------------------------------

四、高精度除法

794. 高精度除法

给定两个非负整数(不含前导 00) A,BA,B,请你计算 A/BA/B 的商和余数。

输入格式

共两行,第一行包含整数 AA,第二行包含整数 BB。

输出格式

共两行,第一行输出所求的商,第二行输出所求余数。

数据范围

1≤A的长度≤1000001≤A的长度≤100000,
1≤B≤100001≤B≤10000,
BB 一定不为 00

输入样例:

7
2

输出样例:

3
1

思路:

1.从最高位开始除,除不尽剩下的r和第二高位结合为r=r*10+a[i];反复此动作即可;

2.注意:除法是从A数组最高位开始做运算;

#include<iostream>
using namespace std;
#include<vector>;
#include<bits/stdc++.h>
int r=0;
vector<int> chu(vector<int> &a,int b)
{
    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());
    while(c.size()>1&&c.back()==0)c.pop_back();
    return c;
}
int main()
{
    vector<int>A;
    string a;
    int b;
    cin>>a>>b;
    for(int i=a.size()-1;i>=0;i--)
    {
        A.push_back(a[i]-'0');
    }
    auto c=chu(A,b);
    for(int i=c.size()-1;i>=0;i--)
    {
        cout<<c[i];
    }
    cout<<endl<<r;
    return 0;
}

 --------------------------------------------------------------------------------------------------------------------------------五、前缀和

795. 前缀和

输入一个长度为 nn 的整数序列。

接下来再输入 mm 个询问,每个询问输入一对 l,rl,r。

对于每个询问,输出原序列中从第 ll 个数到第 rr 个数的和。

输入格式

第一行包含两个整数 nn 和 mm。

第二行包含 nn 个整数,表示整数数列。

接下来 mm 行,每行包含两个整数 ll 和 rr,表示一个询问的区间范围。

输出格式

共 mm 行,每行输出一个询问的结果。

数据范围

1≤l≤r≤n1≤l≤r≤n,
1≤n,m≤1000001≤n,m≤100000,
−1000≤数列中元素的值≤1000−1000≤数列中元素的值≤1000

输入样例:

5 3
2 1 3 6 4
1 2
1 3
2 4

输出样例:

3
6
10

思路:

1.第一项为s[0]=0;

2.s[k]=s[k-1]+a[i]

#include<iostream>
using namespace std;
#include<vector>;
#include<bits/stdc++.h>

int main()
{
    int n,m;
    scanf("%d %d",&n,&m);
    vector<int> a(n);
    int s[n+1];
    s[0]=0;
    for(int i=0;i<n;i++)
    {
        scanf("%d",&a[i]);
        s[i+1]=s[i]+a[i];
    }
    while(m--)
    {
        int k,v;
        scanf("%d %d",&k,&v);
        printf("%d\n",s[v]-s[k-1]);
    }
    return 0;
}

---------------------------------------------------------------------------------------------------------------------------------六、

796. 子矩阵的和

输入一个 nn 行 mm 列的整数矩阵,再输入 qq 个询问,每个询问包含四个整数 x1,y1,x2,y2x1,y1,x2,y2,表示一个子矩阵的左上角坐标和右下角坐标。

对于每个询问输出子矩阵中所有数的和。

输入格式

第一行包含三个整数 n,m,qn,m,q。

接下来 nn 行,每行包含 mm 个整数,表示整数矩阵。

接下来 qq 行,每行包含四个整数 x1,y1,x2,y2x1,y1,x2,y2,表示一组询问。

输出格式

共 qq 行,每行输出一个询问的结果。

数据范围

1≤n,m≤10001≤n,m≤1000,
1≤q≤2000001≤q≤200000,
1≤x1≤x2≤n1≤x1≤x2≤n,
1≤y1≤y2≤m1≤y1≤y2≤m,
−1000≤矩阵内元素的值≤1000−1000≤矩阵内元素的值≤1000

输入样例:

3 4 3
1 7 2 4
3 6 2 8
2 1 2 3
1 1 2 2
2 1 3 4
1 3 3 4

输出样例:

17
27
21

思路: 

1.首先,定义s[n+1][m+1]数组,将其全部赋值为0;

2.将第二行第二列进行第五题的前缀和赋值;

3.如何求s[i][j]? s[i][j]=a[i-1][j-1]-s[i-1][j-1]+s[i][j-1]+s[i-1][j];因为s比a整体每一行列多1;

4.如何求和?t=s[x2][y2]+s[x1-1][y1-1]-s[x1-1][y2]-s[x2][y1-1];记住不要将x1,y1放在被减的列表里;

#include<iostream>
using namespace std;
#include<vector>;
#include<bits/stdc++.h>

int main()
{
    int n,m,q;
    scanf("%d %d %d",&n,&m,&q);
    int a[n][m];
    int s[n+1][m+1];
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            scanf("%d",&a[i][j]);
        }
    }
    for(int i=0;i<=n;i++)
    {
        for(int j=0;j<=m;j++)
        {
            s[i][j]=0;
        }
    }

    s[1][1]=a[0][0];
    for(int i=1;i<=n;i++)
    {
        s[i][1]=s[i-1][1]+a[i-1][0];
    }
    for(int i=1;i<=m;i++)
    {
        s[1][i]=s[1][i-1]+a[0][i-1];
    }
    //cout<<endl;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            s[i][j]=a[i-1][j-1]-s[i-1][j-1]+s[i][j-1]+s[i-1][j];
        }
    }
    /*for(int i=0;i<n+1;i++)
    {
        for(int j=0;j<m+1;j++)
        {
            cout<<s[i][j]<<" ";
        }
        cout<<endl;
    }*/
    while(q--)
    {
        int x1,y1,x2,y2;
        scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
        int t=s[x2][y2]+s[x1-1][y1-1]-s[x1-1][y2]-s[x2][y1-1];
        printf("%d\n",t);
    }
    return 0;
}

---------------------------------------------------------------------------------------------------------------------------------

七、

797. 差分

输入一个长度为 nn 的整数序列。

接下来输入 mm 个操作,每个操作包含三个整数 l,r,cl,r,c,表示将序列中 [l,r][l,r] 之间的每个数加上 cc。

请你输出进行完所有操作后的序列。

输入格式

第一行包含两个整数 nn 和 mm。

第二行包含 nn 个整数,表示整数序列。

接下来 mm 行,每行包含三个整数 l,r,cl,r,c,表示一个操作。

输出格式

共一行,包含 nn 个整数,表示最终序列。

数据范围

1≤n,m≤1000001≤n,m≤100000,
1≤l≤r≤n1≤l≤r≤n,
−1000≤c≤1000−1000≤c≤1000,
−1000≤整数序列中元素的值≤1000−1000≤整数序列中元素的值≤1000

输入样例:

6 3
1 2 2 1 2 1
1 3 1
3 5 1
1 6 1

输出样例:

3 4 5 3 4 2

 思路:

1.求出差分数组chafen(),chafen(i,i,a[i]);;

2.将b变为自己的后缀和数组

3.输出b

#include<iostream>
using namespace std;
#include<vector>;
#include<bits/stdc++.h>
int a[100000],b[100000];
void chafen(int l,int r,int k)
{
    b[l]+=k;
    b[r+1]-=k;
}

int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=0;i<n;i++)
    {
        cin>>a[i];
    }
    for(int i=0;i<n;i++)
    {
        chafen(i,i,a[i]);
    }

    while(m--)
    {
        int l,r,k;
        cin>>l>>r>>k;
        chafen(l-1,r-1,k);
    }
    for(int i=1;i<n;i++)b[i]=b[i-1]+b[i];
    for(int i=0;i<n;i++)cout<<b[i]<<" ";
}

---------------------------------------------------------------------------------------------------------------------------------

八、

798. 差分矩阵

输入一个 nn 行 mm 列的整数矩阵,再输入 qq 个操作,每个操作包含五个整数 x1,y1,x2,y2,cx1,y1,x2,y2,c,其中 (x1,y1)(x1,y1) 和 (x2,y2)(x2,y2) 表示一个子矩阵的左上角坐标和右下角坐标。

每个操作都要将选中的子矩阵中的每个元素的值加上 cc。

请你将进行完所有操作后的矩阵输出。

输入格式

第一行包含整数 n,m,qn,m,q。

接下来 nn 行,每行包含 mm 个整数,表示整数矩阵。

接下来 qq 行,每行包含 55 个整数 x1,y1,x2,y2,cx1,y1,x2,y2,c,表示一个操作。

输出格式

共 nn 行,每行 mm 个整数,表示所有操作进行完毕后的最终矩阵。

数据范围

1≤n,m≤10001≤n,m≤1000,
1≤q≤1000001≤q≤100000,
1≤x1≤x2≤n1≤x1≤x2≤n,
1≤y1≤y2≤m1≤y1≤y2≤m,
−1000≤c≤1000−1000≤c≤1000,
−1000≤矩阵内元素的值≤1000−1000≤矩阵内元素的值≤1000

输入样例:

3 4 3
1 2 2 1
3 2 2 1
1 1 1 1
1 1 2 2 1
1 3 2 3 2
3 1 3 4 1

输出样例:

2 3 4 1
4 3 4 1
2 2 2 2

思路:

1.由图,将b[i][j]+c时,对应是s(1,2,3,4)区域全部加c,此时要减去s(2,4)和s(3,4)的值并且加上s4的值即可。即对应:

    b[x1][y1]+=k;
    b[x2+1][y2+1]+=k;
    b[x1][y2+1]-=k;
    b[x2+1][y1]-=k;

当chafen(i,j,i,j,a[i][j])时,可以理解为将大矩形缩成一个格子求得b[i][j]

2.最后,使用前缀和b[i][j]+=b[i-1][j]+b[i][j-1]-b[i-1][j-1]将b本身变成前缀和函数,再对应输出即可;

#include<iostream>
using namespace std;
#include<vector>;
#include<bits/stdc++.h>
int a[1010][1010],b[1010][1010];
void chafen(int x1,int y1,int x2,int y2,int k)
{
    b[x1][y1]+=k;
    b[x2+1][y2+1]+=k;
    b[x1][y2+1]-=k;
    b[x2+1][y1]-=k;
}

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++)
        {
            chafen(i,j,i,j,a[i][j]);
        }
    }
    while(q--)
    {
        int x1,y1,x2,y2,c;
        cin>>x1>>y1>>x2>>y2>>c;
        chafen(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];
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            cout<<b[i][j]<<" ";
        }
        cout<<endl;
    }
    return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值