差分

797. 差分

题目链接

模板题:根据原数组构造差分数组,原数组为差分数组的前缀和数组

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

using namespace std;

const int N = 1e5 + 10;

int a[N], b[N];
int l, r, c;
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 ++){
        int x;
        scanf("%d", &x);
        insert(i, i, x);
    }
    while(m --){
        scanf("%d%d%d", &l, &r, &c);
        insert(l, r, c);
    }
    for(int i = 1; i <= n; i ++) a[i] = a[i - 1] + b[i];
    for(int i = 1; i <= n; i ++) printf("%d ", a[i]);
    
    return 0;
}

增减序列

题目链接

  • 差分序列的含义:
    b[i]={a[i]i=1a[i]a[i1]i2

  • 原序列与差分序列的对应关系:

a[0] a[1] a[2] ... a[n] 0
0 a[1] - a[0] a[2] - a[1] ... a[n] - a[n - 1] 0

完整的差分数组有n + 1项,b[0]和b[n + 1]都为0,通过差分数组可以对原数组的任意一段同时加上或减去某个值。

  • 具体规则如下:

Ac代码

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

using namespace std;

typedef long long ll;

const int N = 1e5 + 10;

ll a[N], b[N];
int n;

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

int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i ++){
        ll x;
        scanf("%lld", &x);
        insert(i, i, x);
    }
    //for(int i = 1; i <= n; i ++) printf("%d ", b[i]);
    ll sum1 = 0, sum2 = 0;
    for(int i = 2; i <= n; i ++)
        if(b[i] < 0) sum1 += b[i];
        else sum2 += b[i];
    printf("%lld\n", abs(sum1 + sum2) + min(-sum1, sum2));
    printf("%lld\n", abs(sum1 + sum2) + 1);
    return 0;
}

101.最高的牛

题目链接 https://www.acwing.com/problem/content/description/103/

解析

  • 假设所有牛都是最大身高,如果(l, r)之间的牛可以看见,则insert(l + 1, r - 1, -1)
  • 有两个坑点,一个是(l, r)的大小关系记得swap,另一个是对于可见关系描述可能重复,要先加入集合去重

Ac代码

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

using namespace std;

typedef pair<int, int> PII;

const int N = 1e4 + 10;

#define x first
#define y second

int n, p, h, m;
int a[N], b[N];
set<PII> ss;

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

int main()
{
    scanf("%d%d%d%d", &n, &p, &h, &m);
    for(int i = 1; i <= n; i ++) insert(i, i, h);
    while(m --){
        int l, r;
        scanf("%d%d", &l, &r);
        if(l > r) swap(l, r);
        ss.insert({l, r});
    }
    
    for(auto i : ss){
        insert(i.x + 1, i.y - 1, -1);
    }
    for(int i = 1; i <= n; i ++) a[i] = a[i - 1] + b[i];
    for(int i = 1; i <= n; i ++) printf("%d\n", a[i]);
    
    return 0;
}

4007. 非零段划分

题目链接
https://www.acwing.com/problem/content/4010/
解析
image
Ac代码

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

using namespace std;

const int N = 5e5 + 10;
const int M = 1e4 + 10;

int a[N];
int b[N];
int n;

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

int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
    for(int i = 1; i <= n; i ++){
        if(a[i] > a[i - 1]) insert(a[i - 1], a[i] - 1, 1);
    }
    int ans = 0, res = 0;
    for(int i = 0; i <= M; i ++){
        ans += b[i];
        res = max(ans, res);
    }

    printf("%d\n", res);
    
    return 0;
}

2014. 岛

题目链接
https://www.acwing.com/problem/content/2016/

解析
与非零段划分方法相同,唯一区别在于使用map进行离散化,得到差分的map,注意map的遍历方法,可以用map是因为map默认按照第一维排序。

Ac代码

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

using namespace std;

const int N = 1e5 + 10;

typedef long long ll;

map<ll, ll> mp;
int n;
ll a[N];

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

int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i ++) scanf("%lld", &a[i]);
    for(int i = 1; i <= n; i ++){
        if(a[i] > a[i - 1]){
            insert(a[i - 1], a[i] - 1, 1);
        }
    }
    ll ans = 0, res = 0;
    for(auto t : mp){
        ans += t.second;
        res = max(ans, res);
    }
    printf("%lld\n", res);
    return 0;
}

1952 金发姑娘和N头牛

题目链接
https://www.acwing.com/problem/content/1954/
解析
与岛、非零段划分相同,都是算序列中每一个元素对于答案的贡献,最终形成一个横坐标为温度t的数组,然后遍历取最大值即可。本题和岛都需要用map离散化,目的在于按从小到大的顺序枚举温度t,算出最大的产值。
Ac代码

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

using namespace std;

typedef long long ll;

int n, x, y, z;
ll mmin, mmax;
map<ll, ll> mp;

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

int main()
{
    scanf("%d%d%d%d", &n, &x, &y, &z);
    for(int i = 1; i <= n; i ++){
        scanf("%lld%lld", &mmin, &mmax);
        insert(0, mmin - 1, x);
        insert(mmin, mmax, y);
        insert(mmax + 1, 1e9, z);
    }
    ll ans = 0, res = 0;
    for(auto i : mp){
        ans += i.second;
        res = max(ans, res);
    }
    printf("%lld\n", res);
    
    return 0;
}

1715. 桶列表

题目链接
https://www.acwing.com/problem/content/1717/
解析
差分,时间作为横轴
Ac代码

点击查看代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1010;

int a[N], s[N];
int n;

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

int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i ++)
    {
        int x, y, z;
        scanf("%d%d%d", &x, &y, &z);
        insert(x, y, z);
    }
    
    int ans = 0;
    for(int i = 1; i <= N; i ++){  //范围容易写错,不是1~n
        s[i] = s[i - 1] + a[i];
        ans = max(ans, s[i]);
    }
    
    printf("%d\n", ans);
    
    return 0;
}
posted @   小菜珠的成长之路  阅读(39)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示