算法基础——离散化

离散化

此处特指整数的离散化:一个分布较散的数列映射到一个集中的数列上(序列中数的跨度比较大但是很稀疏),如:

a[]  1    3    100  2000 500000
     ↓    ↓    ↓    ↓    ↓
b[]  0    1    2    3    4

会出现以下问题:

  1. a[]中可能有重复元素(去重)
  2. 如何算出a[]离散化之后的值

解决方法:

vector<int> alls;//存储所有待离散化的值
sort(alls.begin(),alls.end())//将所有值排序
alls.erase(unique(alls.begin(),alls.end()),alls.end())//去掉重复元素

//二分求出x对应的离散化的值
int find(int x)
{
    int i=0, r=alls.size()-1;
    while(l<r)
    {
        int mid=l+r>>1;
        if(alls[mid]>=x) r=mid;
        else l=mid+1;
    }
    return r+1;
}

区间和

题目描述

假定有一个无限长的数轴,数轴上每个坐标上的数都是0。

现在,我们首先进行n次操作,每次操作将某一位置x上的数加c。

接下来,进行m次询问,每个询问包含两个整数l和r,你需要求出在区间[l,r]之间的所有数的和。

输入格式

第一行包含两个整数n和m。

接下来n行,每行包含两个整数x和c。

再接下来m行,每行包含两个整数l和r。

输出格式

共m行,每行输出一个询问中所求的区间内数字和。

数据范围

−109≤x≤109,
1≤n,m≤105,
−109≤l≤r≤109,
−10000≤c≤10000

输入样例

3 3
1 2
3 6
7 5
1 3
4 6
7 8

输出样例

8
0
5

题解

数的范围是[−109, 109],所以如果用暴力就会直接爆掉。由于操作的次数是1e5,所以其实数轴上的数最多只会有1e5个需要操作,但是数的范围却分散在整个数轴范围的[−109, 109],所以考虑先对给出操作的数据进行离散化处理,这样可将需要遍历的范围大大缩小。再在处理之后的数据上加上每次操作时加上的c,所有处理完成之后再利用前缀和完成询问。

那么现在要解决三个问题:

  1. 如何实现离散化
  2. 离散化过程中原数组中的元素有重合的情况该如何处理
  3. 如何定位原来的元素在离散化后的新数组中的位置

首先处理第一个问题:离散化处理的过程中我们常常使用vector动态数组进行存储数据。我们将待处理的数据存储在add动态数组中,每组数据以pair的形式存储,first存放出现的需要操作的数xsecond要加上的数c。待询问的数据以相同形式存储在query动态数组中,first存放区间左端点lsecond存放区间右端点r。用int型动态数组存放所有出现过的待离散化的数。在输入时将所有的xlr放到all动态数组中用作接下来的离散化。最后用a数组表示所有处理结束后的结果,用s数组表示它的前缀和。

接下来处理第二个问题:all数组中的重复的元素删除,利用uniqueerase函数。

最后一个问题:我们使用二分查找的方法找到待处理的数xall数组中的位置,并将它的值赋予结果数组a。(由于all动态数组已经过了去重操作所以最后a数组的下标和all相同。)

最后经过前缀和操作完成。

代码

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 3e5 + 7;
int a[N], s[N];
vector<int> all;
vector<pair<int, int>> add, query;
int find(int x)
{
	int l = 0, r = all.size() - 1;
	while (l < r)
	{
		int mid = l + r >> 1;
		if (all[mid] >= x) r = mid;
		else l = mid + 1;
	}
	return r + 1;
}
int main(void)
{
	int n, m;
	cin >> n >> m;
	while (n--)
	{
		int x, c;
		cin >> x >> c;
		add.push_back({ x, c });
		all.push_back(x);
	}
	while (m--)
	{
		int l, r;
		cin >> l >> r;
		query.push_back({ l, r });
		all.push_back(l);
		all.push_back(r);
	}
	//去重
	sort(all.begin(), all.end());
	all.erase(unique(all.begin(), all.end()), all.end());
	//插入
	for (auto i : add) a[find(i.first)] += i.second;
	//预处理前缀和
	for (int i = 1; i <= all.size(); ++i) s[i] = s[i - 1] + a[i];
	//处理询问
	for (auto i : query) cout << s[find(i.second)] - s[find(i.first) - 1] << endl;
	return 0;
}

TIP

unique()函数是一个去重函数,STLunique的函数unique的功能是去除相邻的重复元素(只保留一个)。

还有一个容易忽视的特性是:它并不真正把重复的元素删除,而是把重复的元素移到后面去,依然保存到了原数组中,最后返回去重后最后一个元素的地址。

它是c++中的函数,所以头文件要加#include<iostream>#include<algorithm>,具体用法如下:

因为unique去除的是相邻的重复元素,所以一般使用之前都会要排一下序。

注意:unique函数并非是真正删除了元素,所以一般要与erase成员函数或resize成员函数互相配合使用。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
离散化粒子群算法(Discrete Particle Swarm Optimization,DPSO)是一种基于群体智能的优化算法,可以应用于解决上学优化问题。离散化粒子群算法是粒子群算法(Particle Swarm Optimization,PSO)的一种变体,它将连续空间的搜索问题转化为离散空间的搜索问题。在离散化粒子群算法中,每个粒子代表一个候选解,候选解是由离散的决策变量组成的。每个粒子根据自身的经验和群体的协作,通过更新自身的位置和速度来搜索最优解。 在离散化粒子群算法中,将上学优化问题转化为离散化问题,即将连续的决策变量转化为离散的取值。例如,将决策变量表示为某个学生选择上课时间的离散取值,比如上午、下午或晚上。然后,通过定义适应度函数来评估每个候选解的优劣,适应度函数可根据上学优化问题的具体要求进行设计。 离散化粒子群算法的基本流程如下: 1. 初始化粒子群的位置和速度,以及其他相关参数。 2. 计算每个粒子的适应度值。 3. 更新每个粒子的位置和速度,通过考虑个体最优和群体最优解来更新。 4. 判断停止条件是否满足,如果满足则输出最优解,否则返回第2步。 5. 输出找到的最优解。 通过离散化粒子群算法,可以在离散空间中搜索上学优化问题的最优解。然而,需要注意的是,离散化粒子群算法的性能受到离散化粒子的数量、速度更新策略和适应度函数的选择等因素的影响,需要根据具体问题进行调优。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [【机器学习】汇总——基础](https://blog.csdn.net/linghugoolge/article/details/88337065)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值