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

算法竞赛当中离散化算法的初步介绍和简单应用

如果一个当给定的编号数据范围过于大时,需要用到离散化算法来映射编号,原理大致与哈希表差不多,但是有差别

就比如10000,20000,300000...映射之后就是1代表10000,2代表20000,5代表300000....

主要看你怎么编号,就是把大数据编码为小数据,这个技巧还是很实用的,属于算法竞赛当中的基础内容

802.区间和(离散化 + 前缀和)(模板题)

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

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

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

输入格式

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

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

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

输出格式

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

数据范围

−10^9≤x≤10^9
1≤n,m≤10^5
−10^9≤l≤r≤10^9
−10000≤c≤10000

输入样例:

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

输出样例:

8
0
5

离散化的本质其实就是把大数据编号为小数据,然后通过二分查找找到我们所编码的那个值 

可以先假设一下,如果这道题的数据范围最大是10^3怎么做?是不是就是一个非常简单的前缀和,但是一旦数据量到达10^9这种很大的数据时,就需要先离散化编号一下了

代码模板

#include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>

using namespace std;

typedef pair<int,int> PII;

const int N = 3e5 + 10;
int a[N],b[N];
vector<int> alls;
vector<PII> query,add;

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;
        else l = mid + 1;
    }
    
    return l + 1;
}

int main()
{
    cin >> n >> m;
    for(int i = 0,x,c;i < n;i ++){
        cin >> x >> c;
        alls.push_back(x);
        add.push_back(make_pair(x,c));
    }
    for(int i = 0,l,r;i < m;i ++){
        cin >> l >> r;
        alls.push_back(l),alls.push_back(r);
        query.push_back(make_pair(l,r));
    }
    
    sort(alls.begin(),alls.end());
    alls.erase(unique(alls.begin(),alls.end()),alls.end());
    
    for(auto [x,w] : add) a[find(x)] += w;
    for(int i = 1;i <= alls.size();i ++) b[i] = b[i - 1] + a[i];
    
    for(auto [l,r] : query) cout << b[find(r)] - b[find(l) - 1] << endl;
    
    for(int i = 1;i <= 8;i ++) cout << a[find(i)] << " ";
    
    return 0;
}

103.电影 (简单应用)

莫斯科正在举办一个大型国际会议,有 n 个来自不同国家的科学家参会。

每个科学家都只懂得一种语言。

为了方便起见,我们把世界上的所有语言用 1 到 10^9 之间的整数编号。

在会议结束后,所有的科学家决定一起去看场电影放松一下。

他们去的电影院里一共有 m 部电影正在上映,每部电影的语音和字幕都采用不同的语言。

对于观影的科学家来说,如果能听懂电影的语音,他就会很开心;如果能看懂字幕,他就会比较开心;如果全都不懂,他就会不开心。

现在科学家们决定大家看同一场电影。

请你帮忙选择一部电影,可以让观影很开心的人最多。

如果有多部电影满足条件,则在这些电影中挑选观影比较开心的人最多的那一部。

输入格式

第一行输入一个整数 n,代表科学家的数量。

第二行输入 n 个整数 a1,a2…an,其中 ai 表示第 i 个科学家懂得的语言的编号。

第三行输入一个整数 m,代表电影的数量。

第四行输入 m 个整数 b1,b2…bm,其中 bi 表示第 i 部电影的语音采用的语言的编号。

第五行输入 m 个整数 c1,c2…cm,其中 ci 表示第 i 部电影的字幕采用的语言的编号。

请注意对于同一部电影来说,bi≠ci。

同一行内数字用空格隔开。

输出格式

输出一个整数,代表最终选择的电影的编号。电影编号 1∼m。

如果答案不唯一,输出任意一个均可。

数据范围

1≤n,m≤200000,
1≤ai,bi,ci≤10^9

输入样例:

3
2 3 2
2
3 2
2 3

输出样例:

2

这道题思路很很明显了,如果没有大范围数据其实应该算是入门级别的题,只不过这道题需要离散化一下编号

代码

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

const int N = 6e5 + 10;
int a[N],b[N],c[N];
int cnt[N];
vector<int> alls;

int n,m;
int res = -1;

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;
        else l = mid + 1;
    }
    
    return l;
}

int main()
{
    cin >> n;
    for(int i = 0;i < n;i ++){
        cin >> a[i];
        alls.push_back(a[i]);
    }
    cin >> m;
    for(int i = 0;i < m;i ++){
        cin >> b[i];
        alls.push_back(b[i]);
    }
    for(int i = 0;i < m;i ++){
        cin >> c[i];
        alls.push_back(c[i]);
    }
    
    sort(alls.begin(),alls.end());
    alls.erase(unique(alls.begin(),alls.end()),alls.end());
    
    for(int i = 0;i < n;i ++) cnt[find(a[i])] ++;
    // for(int i = 1;i <= 3;i ++) cout << i << ":" << cnt[find(i)] << " ";
    // cout << endl;
    
    int x = 0,y = 0,idx = 1;
    for(int i = 0;i < m;i ++){
        int A = cnt[find(b[i])],B = cnt[find(c[i])];
        // cout << A << " " << B << endl;
        if(A > x || (A == x && B > y)){
            res = idx;
            x = A, y = B;
        }
        idx ++;
    }
    
    cout << (res == -1 ? 1 : res) << endl;
    return 0;
}

1952.金发姑娘和N头牛(差分 + 离散化)

你可能听过关于金发姑娘和三只熊的经典故事。

然而,鲜为人知的是,金发姑娘最终成了一个农民。

在她的农场中,她的牛棚里有 N 头奶牛。

不幸的是,她的奶牛对温度相当敏感。

对于奶牛 i,使其感到舒适的温度为 Ai…Bi。

如果金发姑娘将牛棚的恒温器的温度 T 设置为 T<Ai,奶牛就会觉得冷,并会产出 X 单位的牛奶。

如果她将恒温器的温度 T 设置在 Ai≤T≤Bi,奶牛就会感到舒适,并会产出 Y 单位的牛奶。

如果她将恒温器的温度 T 设置为 T>Bi,奶牛就会觉得热,并会产出 Z 单位的牛奶。

正如所期望的那样,Y 的值始终大于 X 和 Z。

给定 X,Y,Z 以及每头奶牛感到舒适的温度范围,请计算通过合理设定恒温器温度,金发姑娘可获得的最大产奶量。

恒温器温度可设置为任何整数。

输入格式

第一行包含四个整数 N,X,Y,Z。

接下来 N 行,每行包含两个整数 Ai 和 Bi。

输出格式

输出可获得的最大产奶量。

数据范围

1≤N≤20000
0≤X,Y,Z≤1000
0≤Ai≤Bi≤10^9

输入样例:

4 7 9 6
5 8
3 4
13 20
7 10

输出样例:

31

样例解释

金发姑娘可以将恒温器温度设置为 7 或 8,这样会让奶牛 1 和 4 感到舒适,奶牛 2 感到热,奶牛 3 感到冷。

共可获得 31 单位牛奶。

这道题需要一点点思维,或者说需要有一定的刷题量,一旦算法与算法之间联合起来的时候就很不好想。就比如这个题,只会差分不行,只会离散化也不行,必须这两个算法都掌握的非常牢固

思路就是区间[0,A[i]]全部加X,区间[A[i],B[i]] 全部加Y......将值离散化即可

代码:

#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>

using namespace std;

typedef pair<int,int> PII;

const int N = 4e4 + 10;
int b[N],a[N];
vector<int> alls;
vector<PII> add;

int n,X,Y,Z;
int res = 0;

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;
        else l = mid + 1;
    }
    
    return l + 1;
}

int main()
{
    cin >> n >> X >> Y >> Z;
    for(int i = 0,l,r;i < n;i ++){
        cin >> l >> r;
        alls.push_back(l), alls.push_back(r);
        add.push_back(make_pair(l,r));
    }
    
    sort(alls.begin(),alls.end());
    alls.erase(unique(alls.begin(),alls.end()),alls.end());
    
    for(int i = 0;i < n;i ++){
        auto [l,r] = add[i];
        b[1] += X;
        b[find(l)] += Y - X;
        b[find(r + 1)] += Z - Y;
        b[alls.size() + 1] -= Z;
    }
    
    for(int i = 1;i <= alls.size();i ++){
        a[i] = a[i - 1] + b[i];
        res = max(res,a[i]);
    }
    
    cout << res << endl;
    
    return 0;
}


http://www.kler.cn/a/324461.html

相关文章:

  • Ubuntu安装ollama,并运行ollama和通义千问,使用gradio做界面
  • YOLOv5、YOLOv6、YOLOv7、YOLOv8、YOLOv9、YOLOv10、YOLOv11 推理的 C++ 和 Python 实现
  • [Linux]多线程详解
  • 【MySQL】SQL语言
  • 03-axios常用的请求方法、axios错误处理
  • Elasticsearch retrievers 通常与 Elasticsearch 8.16.0 一起正式发布!
  • 10_React router6
  • React Native 在 build iOS 的时候如果出现关于 `metro` 的错误
  • My_string 运算符重载,My_stack
  • JavaScript 中的闭包的形成及使用场景
  • 代码随想录_刷题笔记_第三次
  • MySQL 高级 - 第十五章 | MySQL 事务日志
  • 完全二叉树的递归创建思路及代码
  • 1Panel安装部署证书(httpsok.com)
  • matlab入门学习(二)矩阵、字符串、基本语句、函数
  • UART驱动学习一(UART硬件介绍)
  • 泛微E8JDK1.6判断时间在早上8点半到晚上六点半之间的值
  • WPF入门教学二十四 WPF性能优化
  • 机器学习与深度学习的技术比较
  • Docker网络、数据卷及安全优化
  • C++学习笔记(39)
  • C#中的报文(Message)
  • 9月29日微语报,星期日,农历八月廿七
  • C++--IO流
  • Eureka原理实践:构建高可用、可扩展的微服务架构
  • .NET 红队武器库和资源集合 (第38期)