首页 > 编程语言 >【基础算法】离散化

【基础算法】离散化

时间:2024-03-03 20:25:57浏览次数:25  
标签:end int 基础 back 离散 算法 alls push

离散化

// 每日一题
#include <bits/stdc++.h>
using namespace std;
const int N = 1000010;
int n, m;
int a[N], d[N], s[N], t[N];
long long b[N];

bool check(int x)
{
	memset(b, 0, sizeof b);
	for (int i = 1; i <= x; i++)
	{
		b[s[i]] += d[i];
		b[t[i] + 1] -= d[i];
	}
	
	for (int i = 1; i <= n; i++) b[i] += b[i - 1];
	
	for (int i = 1; i <= n; i++)
	{
		if (b[i] > a[i]) return false;
	}
	
	return true;
}

int main()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++) cin >> a[i];
	for (int i = 1; i <= m; i++)
	{
		cin >> d[i] >> s[i] >> t[i];
	}
	if (check(m))
	{
		cout << 0 << endl;
		return 0;
	}
	int l = 1, r = m;
	while (l <= r)
	{
		int mid = (l + r) >> 1;
		if (check(mid)) l = mid + 1;
		else r = mid - 1;
	}
	cout << -1 << '\n' << l << endl;
	return 0;
}

为什么要进行离散化?

假如给你一个序列,他的数据范围是 \(-10^9\) ~ \(10^9\) 你要统计它给出的数的个数,你能开数组来存嘛?

那么这样我们就可以讲这么大范围的数给映射到小范围的数里,打个比方,\(-1230384328\) 这个数就可以映射到 \(3\) 那么我们的 \(a[3]=-1230384328\) 我们统计的时候直接 \(cnt[3]++\)

离散化的几个问题

  • 我们怎么快速的映射,并且让映射的数字相互之间不冲突?

    • 排序加去重,使序列升序的排到数组中
  • 我们怎么找到映射后的数字在映射数组的下标?

    • 二分(已经排序了)、哈希表

例题:区间和

// 二分
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
const int N = 300010;
vector<int> alls; // 存离散化之后的值
vector<PII> add, query;
int a[N], s[N];
int n, m;

int find(int x)
{
	int l = 0, r = alls.size() - 1;
	
	while (l <= r)
	{
		int mid = (l + r) >> 1;
		if (alls[mid] > x) r = mid - 1;
		else l = mid + 1;
	}
	return r + 1; // 下标从1开始
}

int main()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
	{
		int x, c;
		cin >> x >> c;
		alls.push_back(x); // 离散化 x
		
		add.push_back({x, c});
	}
	for (int i = 1; i <= m; i++)
	{
		int l, r;
		cin >> l >> r;
		alls.push_back(l); // 离散化l
		alls.push_back(r); // 离散化r
		
		query.push_back({l, r}); // 记录操作
	}
	
	// 离散化过程
	sort(alls.begin(), alls.end());
	alls.erase(unique(alls.begin(), alls.end()), alls.end());
	
	for (auto t : add)
	{
		int x = find(t.first);
		a[x] += t.second;
	}
	
	// 前缀和
	for (int i = 1; i <= (int)alls.size(); i++) s[i] = s[i - 1] + a[i];
	
	// 查询
	for (auto t : query)
	{
		int l = find(t.first), r = find(t.second);
		cout << s[r] - s[l - 1] << endl;
	}
	
	return 0;
}
// 哈希表
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
const int N = 300010;
vector<int> alls; // 存离散化之后的值
vector<PII> add, query;

unordered_map<int, int> mp; // 哈希表

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


int main()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
	{
		int x, c;
		cin >> x >> c;
		alls.push_back(x); // 离散化 x
		
		add.push_back({x, c});
	}
	for (int i = 1; i <= m; i++)
	{
		int l, r;
		cin >> l >> r;
		alls.push_back(l); // 离散化l
		alls.push_back(r); // 离散化r
		
		query.push_back({l, r}); // 记录操作
	}
	
	// 离散化过程
	sort(alls.begin(), alls.end());
	alls.erase(unique(alls.begin(), alls.end()), alls.end());
	
	for (int i = 0; i <= (int)alls.size() - 1; i++) mp[alls[i]] = i + 1; // 映射到下标从1开始
	
	for (auto t : add)
	{
		int x = mp[t.first];
		a[x] += t.second;
	}
	
	// 前缀和
	for (int i = 1; i <= (int)alls.size(); i++) s[i] = s[i - 1] + a[i];
	
	// 查询
	for (auto t : query)
	{
		int l = mp[t.first], r = mp[t.second];
		cout << s[r] - s[l - 1] << endl;
	}
	
	return 0;
}

标签:end,int,基础,back,离散,算法,alls,push
From: https://www.cnblogs.com/yhgm/p/18050609

相关文章

  • 【基础算法】差分
    差分//每日一题#include<bits/stdc++.h>usingnamespacestd;typedeflonglongLL;constintN=200010;intn;inta[N],s[N];intmain(){ cin>>n; for(inti=1;i<=n;i++) { cin>>a[i]; s[i]=s[i-1]+a[i];//前缀和 } L......
  • Java:基础语法
    注释平时我们编写代码,在代码量比较少的时候,我们还可以看懂自己写的,但是当项目结构一旦复杂起来,我们就需要用到一个注释了,注释就类似于我们上学时候写的笔记,我们看着笔记就知道自己写的什么东西了!在程序中也是如此。我们来看一下Java中的注释怎么写,看以下代码:/**@DescriptionH......
  • 【基础算法】二分查找
    二分查找什么是二分?将问题分成两个部分。猜数游戏计算机给你一个范围内的随机数,你要输入一个数,计算机给你反馈是太大了还是太小了,直到你输出正确的答案。怎么设计这个程序呢?#include<iostream>#include<ctime>usingnamespacestd;intmain(){srand(time(NULL));......
  • 【基础算法】二分答案
    二分答案什么是二分答案?将答案区间进行二分,不断缩小答案区间,直到区间缩小到符合题意的答案。我们又该怎么书写呢?常用的二分模版://不断缩小答案区间while(l<=r){intmid=l+r>>1;if(check(mid))r=mid-1;elsel=mid+1;}模版的含义\(......
  • nginx系列文章01---基础知识
    1.何为反向代理?在介绍反向代理之前,先来了解一下正向代理。正向代理:如果把局域网外的Internet想象成一个巨大的资源库,则局域网中的客户端要访问Internet,则需要通过代理服务器来访问,这种代理服务就称为正向代理,下面是正向代理的原理图。由于工作环境原因,日常工作只能局限于单位的......
  • 如何判断算法的好坏?
    事后统计法(直接运行两个算法程序后比较运行速度)1.过于依赖测试数据 2.过于依赖硬件条件事前分析法     时间复杂度  大O表示法  ......
  • 动手学强化学习(五):时序差分算法
    第5章时序差分算法5.1简介第4章介绍的动态规划算法要求马尔可夫决策过程是已知的,即要求与智能体交互的环境是完全已知的(例如迷宫或者给定规则的网格世界)。在此条件下,智能体其实并不需要和环境真正交互来采样数据,直接用动态规划算法就可以解出最优价值或策略。这就好比对于......
  • 手写HashMap基础部分代码
    代码展示:packagecom.north.hashmap;importjava.util.Map;/***@AuthorNorth*@Date2024/3/3*手写HashMap*/@SuppressWarnings("all")publicclassMyHashMap<K,V>{/***哈希表*/privateNode<K,V>[]table;......
  • Nestjs系列 Nestjs基础(二)
    providers使用该内容可以结合Nestjs中文网-自定义提供者查看创建一个nest项目,创建一个Personcrud模块。providers写法providers完整和简写@Injectable()装饰器将PersonService类标记为提供者。然后在Module中声明,即和PersonService做关联,个人感觉provider......
  • 【Java基础】Maven入门笔记
    本篇笔记参考尚硅谷Maven课程,概括总结了Maven的核心功能Maven仓库地址:MavenRepository:Search/Browse/Explore一、Maven简介1.Maven是一个依赖管理工具、构建工具2.Maven介绍Maven是一款为Java项目管理构建、依赖管理的工具(软件),使用Maven可以自动化构建、测试、打......