当前位置: 首页 > news >正文

蓝桥备赛(25)算法篇【差分】

一、差分

前缀和和差分的核心思想是预处理 可以在暴力枚举的过程中 , 快速给出查询结果 , 从而优化时间复杂度 。

最经典的用空间替换时间的做法。

学完差分之后 , 大家会发现 , 前缀和与差分是一对互逆的运算

二、一维差分

登录—专业IT笔试面试备考平台_牛客网

解法一:暴力解法 --> 直接模拟

两层 for 循环 -->  O(m*n) = 10^10 (超时了...) 

所以我们可以总结出 用差分解决问题的模板:

1) 创建差分数组

 

2)利用差分数组处理 m 次 修改操作


3)还原成原始数组:

#include <iostream>
using namespace std;

typedef long long LL;
const int N = 1e5 + 10;
LL n,m;
LL a[N];
LL f[N];//记录差分数组
 
int main()
{
	cin >> n >> m;
	//利用差分数组定义创建差分数组
	for(int i = 1;i<=n;i++)
	{
		cin >> a[i];
		f[i] = a[i] - a[i-1];
	}
	
	//处理 m 次修改操作
	while(m--)
	{
		LL l,r,k;
		cin >> l >> r >> k;
		f[l] += k;
		f[r+1] -= k;
	} 
	 
	 //还原出原始的数组
	 for(int i = 1;i<=n;i++)
	 {
	 	a[i] = a[i-1] + f[i];
	 	cout << a[i] << " ";
	 }
	  
	return 0;
}

三、海底高铁

P3406 海底高铁 - 洛谷

#include <iostream>
using namespace std;

typedef long long LL;

const int N = 1e5 + 10;

int n,m;
LL f[N];//差分数组 

int main()
{
	cin >> n >> m;
	//x->y
	int x,y;
	cin >> x;
	//处理差分数组 
	for(int i = 2;i<=m;i++)
	{
		cin >> y;
		//x->y
		if(x > y)f[y]++,f[x]--;
		else f[x]++,f[y]--;
		x = y;
	}
	
	//利用差分数组,还原出原数组
	for(int i = 1;i<=n;i++)
	{
		f[i] += f[i-1];
	 } 
	 
	 //直接求结果
	 LL ret = 0;
	 for(int i = 1;i<=n;i++)
	 {
	 	LL a,b,c;
	 	cin >> a >> b >> c;
	 	ret += min(a*f[i],c+b*f[i]);
	  } 
	  cout << ret << endl;
	return 0;
 } 

四、二维差分

登录—专业IT笔试面试备考平台_牛客网

第一个能想到的就是暴力枚举 , 到了目标区域 , 直接进行操作,

但是时间复杂度太高了 , OJ平台是不会给过的~

借助二维差分数组 :

画图 ! 了解二维差分数组的性质 , 等再次使用的时候 , 上手会很快!!!

#include <iostream>
using namespace std;

typedef long long LL;
const int N = 1001;
LL n,m,q;
LL f[N][N];//差分矩阵 

//差分矩阵的性质 
void insert(int x1,int y1,int x2, int y2,int k)
{
	f[x1][y1] += k;
	f[x1][y2+1] -= k;
	f[x2+1][y1] -=k;
	f[x2+1][y2+1] +=k; 
}

int main()
{
	cin >> n >> m >> q;
	//预处理--构造差分矩阵 
	for(int i = 1;i<=n;i++)
	{
		for(int j = 1;j<=m;j++)
		{
			LL x;cin >> x;
			//[i,j] 为左上角,[i,j]为右下角的矩阵,统一加上x
			insert(i,j,i,j,x); 
		}
	}
	
	//处理q次修改操作
	while(q--)
	{
		int x1,y1,x2,y2,k;
		cin >> x1 >> y1 >> x2 >> y2 >> k;
		insert(x1,y1,x2,y2,k);
	 } 
	 
	 //利用前缀和还原修改之后的数组
	 for(int i = 1;i<=n;i++)
	 {
	 	for(int j = 1;j<=m;j++)
	 	{
	 		f[i][j] = f[i-1][j] + f[i][j-1] - f[i-1][j-1] + f[i][j];
	 		cout << f[i][j] << " ";
		 }
		 cout << endl;
	  } 
	
	return 0;
}

五、地毯

P3397 地毯 - 洛谷

差分数组走起来 , 简简单单~ 

#include <iostream>
using namespace std;

const int N = 1010;
int f[N][N];
int n,m; 

void insert(int x1,int y1,int x2,int y2)
{
	f[x1][y1]++;
	f[x2+1][y1]--;
	f[x1][y2+1]--;
	f[x2+1][y2+1]++;
}
int main()
{
	cin >> n >> m;
	while(m--)
	{
		int x1,y1,x2,y2;
		cin >> x1 >> y1 >> x2 >> y2;
		insert(x1,y1,x2,y2);
	}
	
	//借助前缀和还原成原数组
	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] + f[i][j];
			cout << f[i][j] << " ";	
		}
		cout << endl;
	}
	return 0;
}

 在理解的基础上可以背背 , 但是尽量不要背 , 理解为主

相关文章:

  • word文件转换为Markdown格式
  • 关于极端场景下,数据库更新与 MQ 消息一致性保障方案的详细总结
  • Qt信号与槽高级特性与项目实战:原理剖析与工程化应用指南
  • 20250330 Pyflink with Paimon
  • rocky linux下载软件
  • [Python]代理批量检测延迟工具
  • ChatTTS:对话场景语音合成的开源新星
  • 《量子密码》
  • CSS3学习教程,从入门到精通,CSS3 图像属性知识点及案例代码(16)
  • 如何获取thinkphp的所有发行版本
  • 运行时智控:PanLang 开发者指南(一)运行时系统核心模块实现——PanLang 原型全栈设计方案与实验性探索5
  • 单链表中的递归算法
  • 编译原理——词法分析
  • GD32 ARM单片机开发规范检查清单 GD32嵌入式C代码检查清单
  • 《TypeScript 类的艺术:高效编码指南》
  • TransformersInternLM源码阅读
  • 括弧匹配检验(信息学奥赛一本通-1354)
  • Cherry Studio搭建本地知识库,结合DeepSeek实现RAG
  • AM32-MultiRotor-ESC项目固件编译和烧录方法介绍
  • 【Spring】Spring框架介绍
  • 网商银行2024年年报发布,客户资产管理规模超过1万亿
  • 陕西省通报6起违反八项规定典型问题,省卫健委原主任刘宝琴违规收受礼品礼金
  • 辽宁省委书记、省长连夜赶赴辽阳市白塔区火灾事故现场,指导善后处置工作
  • 习近平在上海考察时强调,加快建成具有全球影响力的科技创新高地
  • 餐饮店直播顾客用餐,律师:公共场所并非无隐私,需对方同意
  • 人社部:我国劳动力市场潜力足,韧性强