• 算法竞赛进阶指南0.3 前缀和与差分


    注:此博客为学习acwing视频的随手的笔记

    目录

    1.激光炸弹 (二维前缀和) 

    2. IncDec序列 (差分

    3. Tallest Cow (差分

     

     

    前缀和与差分

    前缀和与差分是一个互逆的运算。

    二维前缀和:

    1)

    for(int i = 1 ; i <= n ; i ++)     //二维前缀和

            for(int j = 1 ; j <= m ; j ++)

                sum[i][j] += sum[i -  1][j] + sum[i][j - 1] - sum[i - 1][j - 1];

    2)

    for(int i=1;i<=n;i++)

            for(int j=1;j<=m;j++)

                sum[i][j] +=sum[i][j-1];

        for(int i=1;i<=n;i++)

            for(int j=1;j<=m;j++)

                sum[i][j] += sum[i-1][j];

    1.激光炸弹 (二维前缀和)

    #include <iostream>

    #include <cstdio>

    using namespace std;

    const int maxn = 5005;

    typedef long long ll;

    int N , R ;

    int sum[maxn][maxn];

    int main(){

        cin.sync_with_stdio(false);

        cin.tie(0);

        cin >> N >> R;

        int n = R , m = R;

        for(int i = 0 ; i < N ; i ++){

            int x, y, z;

            cin >> x >> y >> z;

            sum[++x][++y] =  z;  //从 1 开始 不需要再处理边界问题

            n = max(n , x) , m = max(m , y);  //这道题的长宽需要自己判

        }

        for(int i = 1 ; i <= n ; i ++)     //二维前缀和

            for(int j = 1 ; j <= m ; j ++)

                sum[i][j] += sum[i -  1][j] + sum[i][j - 1] - sum[i - 1][j - 1];

        int ans = 0;

        for(int i = R ; i <= n ; i ++)

            for(int j = R ; j <= m ; j++)

                ans = max(ans , sum[i][j] - sum[i - R][j] - sum[i][j - R] + sum[i - R][j - R]);

        cout << ans << endl;

        return 0;

    }

    2. IncDec序列 (差分)

    差分: 前缀和的逆运算 

    a[1] , a[2] , a[3] , a[4] , ... , a[n]

    b[i] = a[i] - a[i - 1]  b[1] = a[1]

    ba的差分序列 ab的前缀和序列

    O(1) 给区间[l , r]加上一个常数C :

    b[l] += C , b[r + 1] -= C

    它的效果就是前缀和序列al ~rC 其它不影响

     

     

    1. 先求出序列的差分序列b
    2. 做以下操作 使得 b[2] ~b[n]变为0

    1) 选择两个数 2 <= i j <= n   b[i] += 1  b[j] -= 1 b[i] -= 1  b[j] += 1

    2) i = 1 , 2 <= j <= n    

    3) 2 <= i <= n , j = n + 1

    4) i = 1 , j = n + 1 (无意义)

    贪心1) 操作 前面加1 后面-1这样的    (可以保证最小次数)

    操作1最多能够选择 min(差分序列正数和 , 差分序列负数绝对值和)

    若正数多了 则进行操作二  操作三 均可

    例如:操作1结束后 , 正数还剩5 ,那么可以选择

    0次操作二 , 5次操作三 1次操作二 , 4次操作三

    2次操作二 , 3次操作三 3次操作二 , 2次操作三

    4次操作二 , 1次操作三 5次操作二 , 0次操作三

    六种方式 六种结果

    综上 : 最小操作次数 = 操作1 + 操作2,3

    = min(正数的和 , 负数的和的绝对值) + abs(正数的和-负数的和的绝对值)

    方案数 =   abs(正数的和-负数的和的绝对值) + 1

    代码

    #include <iostream>

    #include <algorithm>

    using namespace std;

    const int maxn = 100050;

    int a[maxn];

    typedef long long ll;

    int main(){

        cin.sync_with_stdio(false);

        cin.tie(0);

        int n;

        cin >> n;

        for(int i = 1 ; i <= n ; i ++) cin  >> a[i];

        for(int i = n ; i > 1 ; i --) a[i] -=  a[i - 1];   // 求差分序列

        ll pos = 0 , neg = 0; //pos 正数和  neg 负数和

        for(int i = 2 ; i <= n ; i++){

            if(a[i] > 0 ) pos += a[i];

            else neg -= a[i];

        }

        cout << min(pos , neg) + abs(pos - neg) <<endl;

        cout << abs(pos - neg) + 1 <<endl;

        return 0;

    }

    3. Tallest Cow (差分)

    分析 :任意一对Ai , Bi不可能发生交叉

     

    只可能:

    问题转换成 一个序列所有元素都是 H 的序列 , 给的每一个关系A B(A, B)之间的元素都 -1 ,问每个数最终是多少

    #include <iostream>

    #include <cstdio>

    #include <algorithm>

    #include <set>

    #include <cstring>

    using namespace std;

    const int maxn = 100005;

    int n , i , h , r , sum[maxn];

    set<pair<int,int> > s;

    int main(){

        memset(sum , 0 , sizeof sum);

        cin >> n >> i >> h >> r;

        sum[1] = h;

        for(int i = 0 ; i < r ; i ++){

            int x , y;

            cin >> x >> y;

            if(x == y) continue;

            if(x > y) swap(x , y);

            if(s.find(make_pair(x,y))!=s.end()) continue;

            s.insert(make_pair(x,y));

            sum[x + 1] -= 1;

            sum[y] += 1;

        }

        for(int i = 1 ; i <= n ; i ++) sum[i] += sum[i - 1];

        for(int i = 1 ; i <= n ; i ++) cout << sum[i] <<endl;

    }

  • 相关阅读:
    Mac OS系统安装pymssql 报错
    odoo源生打印【web report】
    《动手学深度学习》task05课后习题
    《动手学深度学习》task05笔记
    《动手学深度学习》task03课后习题
    《动手学深度学习》task03笔记
    《动手学深度学习》task04笔记
    《动手学深度学习》task04课后习题
    《动手学深度学习》task01-02疑难杂症
    《动手学深度学习》task01-02笔记
  • 原文地址:https://www.cnblogs.com/hao-tian/p/11241232.html
Copyright © 2020-2023  润新知