差分
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;
}
增减序列
题目链接
-
差分序列的含义:
-
原序列与差分序列的对应关系:
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/
解析
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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架