算法复盘——差分

一、思路

一维差分:

核心作用

区间 l, r 加 c 这种操作,从 O (n) 降到 O(1)

核心公式

  • 差分数组:diff[i] = a[i] - a[i-1]
  • 区间加:diff[l] += cdiff[r+1] -= c
  • 还原原数组:求前缀和

二维数组:

核心作用

子矩阵矩形区域统一加 c,O (1) 完成。

核心公式

复制代码
diff[x1][y1] += c
diff[x1][y2+1] -= c
diff[x2+1][y1] -= c
diff[x2+1][y2+1] += c

最后用二维前缀和还原。

二、例题

1.语文成绩

P2367 语文成绩 - 洛谷

思路:

  • 初始有 n 个学生成绩,需要执行 p 次「给第 x 到第 y 个学生每人加 z 分」的操作。
  • 最后要输出全班的最低分

分析:

题目的要求即区间修改 和 单点查询,可利用差分数组来处理区间修改,然后使用前缀和还原原数组,查找最小值。

代码实现:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N = 5e6 + 10; 
int n, p, g[N], f[N], gmin = 100;
signed main()
{
	cin >> n >> p;
	for(int i = 1; i <= n; i++)
	{
		cin >> g[i];
		f[i] = g[i] - g[i-1];
	}
	while(p--)
	{
		int l, r, x;
		cin >> l >> r >> x;
		f[l] += x, f[r+1] -= x;
	}
	for(int i = 1; i <= n; i++)
	{
		g[i] = g[i-1] + f[i];
		gmin = min(gmin, g[i]);
	}
	cout << gmin << endl;
	return 0;
}

2.海底高铁

P3406 海底高铁 - 洛谷

思路:

依次经过若干城市,每段相邻城市之间的铁路会被多次经过 ,我们需要先统计出每段铁路被经过多少次

分析:

从城市 x 走到 y,等价于对区间 x, y−1 的铁路都经过一次。

代码实现:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N = 1e5 + 10;
int n, m, f[N], a, b, c, ret;
int x, y;
signed main ()
{
	cin >> n >> m;
	cin >> x;
	for(int i = 2; i <= m; i++)
	{
		cin >> y;
		if(x < y) f[x]++, f[y]--;
		if(x > y) f[y]++, f[x]--;
		x = y;
	}
	for(int i = 1; i <= n; i++) f[i] += f[i-1];
	for(int i = 1; i < n; i++)
	{
		cin >> a >> b >> c;
		ret += min(a * f[i], c + f[i] * b);
	}
	cout << ret << endl;
	return 0;
}

3.借教室

P1083 NOIP 2012 提高组 借教室 - 洛谷

思路:

按顺序处理若干借教室订单,每个订单需要在第 s 天到第 t 天每天借用 d 间教室。若某一天所需教室超过现有数量,则该订单无法满足,要求找到第一个无法满足的订单编号

分析:

订单越多,每天的教室需求只会增加不会减少,因此满足情况呈现单调性:前 k 个可满足 → 所有更小编号都可满足;前 k 个不可满足 → 所有更大编号都不可满足。可用二分答案定位第一个不满足的订单。

对二分出的前 mid 个订单,用差分快速统计每天教室总需求,前缀和还原得到每天实际需求,判断是否存在某天超过可用教室数。

代码实现:

cpp 复制代码
// 暴力
#define int long long 
const int N = 1e6 + 10;
int n, m, r[N], f[N]; 

signed main()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++) cin >> r[i];
	// 初始化差分数组
	for (int i = 1; i <= n; i++) f[i] = r[i] - r[i-1];
	f[n+1] = -r[n];
	
	for (int k = 1; k <= m; k++) {
		int d, s, t;
		cin >> d >> s >> t;
		// 差分标记这个订单
		f[s] -= d;
		f[t+1] += d;
		
		// 前缀和检查是否有天不够
		int now = 0;
		bool ok = true;
		for (int i = 1; i <= n; i++) {
			now += f[i];
			if (now < 0) {
				cout << -1 << endl << k << endl;
				return 0;
			}
		}
	}
	cout << 0 << endl;
	return 0;
}
cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

const int N = 1e6 + 10;
int n, m;
int r[N], d[N], s[N], t[N];
long long diff[N];  // 用long long防止溢出

// 检查前k个订单是否可行
bool check(int k) {
    memset(diff, 0, sizeof(diff));
    // 差分标记前k个订单
    for (int i = 1; i <= k; i++) {
        diff[s[i]] += d[i];
        diff[t[i] + 1] -= d[i];
    }
    // 前缀和还原,判断是否超量
    long long now = 0;
    for (int i = 1; i <= n; i++) {
        now += diff[i];
        if (now > r[i]) return false;
    }
    return true;
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    cin >> n >> m;
    for (int i = 1; i <= n; i++) cin >> r[i];
    for (int i = 1; i <= m; i++) cin >> d[i] >> s[i] >> t[i];
    
    // 二分找第一个不可行的订单
    int l = 1, r = m, ans = 0;
    while (l <= r) {
        int mid = (l + r) >> 1;
        if (check(mid)) {
            ans = mid;
            l = mid + 1;
        } else {
            r = mid - 1;
        }
    }
    
    if (ans == m) cout << 0 << endl;
    else {
        cout << -1 << endl;
        cout << ans + 1 << endl;
    }
    return 0;
}

4.地毯

P3397 地毯 - 洛谷

代码实现:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;


const int N = 1010;
int f[N][N];

int main ()
{
	int m, n; cin >> n >> m;
	
	while(m--)
	{
		int x1, x2, y1, y2; cin >> x1 >> y1 >> x2 >> y2;
		f[x1][y1] ++;
		f[x1][y2 + 1] --;
		f[x2 + 1][y1] --;
		f[x2 + 1][y2 + 1] ++;
	}
	
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= n; j++)
		{
			f[i][j] += f[i-1][j] + f[i][j-1] - f[i-1][j-1];
			cout << f[i][j] << " ";
		}
		cout << endl;
	}
	
	return 0;
}
相关推荐
2501_9269783319 小时前
以说明书 DNA 为模板——完整 AGI 的结构图景
前端·人工智能·经验分享·笔记·ai写作
天天爱吃肉821819 小时前
商用车多体动力学实战笔记|第6篇:动力传动系统(发动机、变速箱、分动器、TCS、LSD限滑差速)
大数据·人工智能·笔记·python·嵌入式硬件·汽车
IT199520 小时前
Dify 实战笔记:工作流核心玩法 + 开源 AI 应用全解析
笔记
MartinYeung520 小时前
[论文学习]OSReward:为跨平台计算机使用奖励模型建立标准化评估
人工智能·学习
dong13269720 小时前
Agent Skills学习笔记
笔记·学习
清水迎朝阳21 小时前
客户端软件 — 用户统计方案
服务器·c++·客户端·用户统计
Re.不晚21 小时前
挑战做100道力扣算法- DAY1
算法·leetcode·职场和发展
for_ever_love__21 小时前
iOS:网络请求再学习
网络·学习·ios·objective-c
蓝悦无人机21 小时前
《Planning algorithms》读书笔记——第1章 引言
算法·读书笔记·规划算法·lavalle
世人万千丶1 天前
鸿蒙Crash高级捕获与异常监控:全局异常兜底/崩溃栈解析/符号表还原/智能聚类/闭环修复
学习·机器学习·华为·数据挖掘·harmonyos·鸿蒙·聚类