随便说说——离散化
Posted fallen-down
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了随便说说——离散化相关的知识,希望对你有一定的参考价值。
本文并非完全原创,引用的其他博客的代码详见最下方。若有侵权行为会第一时间修改。
前记——
最近机房考试,周围的大佬都用了巧妙的方法做了一道我认为需要离散化(而且当时我还不会)(尽管现在也好不到哪里去)的题目
本蒟蒻十分荣幸的因此WA了。所以我决定将错就错,不去想正解了,在岔路上且行且歌
—————————————————————————————————————前置内容—————————————————————————————————————————
-
为什么要离散化
当题目中给你一个数据,你想要以此为根基开数组,你应该怎么办
- 抱头苦想,换一种算法,规避这个数组(CDQ//利用数据结构优化//用bool)
- 离散化大法好
-
离散化前提
- 你数组开不下了
- 但你在计算中,只在意元素之间的相对大小,但不在意其真实大小时
——————————————————————————————————————正文——————————————————————————————————————————
这篇文章要收录三种离散化的方式。下面我将以我自己的使用频率来一一介绍(其实并没有用过太多)
-
STL——map
不知道怎么说明,先设置一个小情景吧:
有标号N(N<=1,000,000,000)的人,任意(每个号可能被抽中两次)抽出25个人,问谁被抽中次数最多;
首先你不可能成为桶哥,其次你要直接用map存我也拦不住你,可我们在搞离散化,所以,,,
for(i=1;i<=n;i++){
scanf("%d",&kc);
if(!a.count(kc)) {
ff++;
a[kc]=ff;
f[ff]++;
}
f[a[kc]]++;
}
首先输入人的编号——kc,其次再看map<int,int>a 中是否出现过;
如果没有出现过,(ff++)——代表新出现一个数,他的编号就是他是第几个新出现的;
如果出现过,则把kc离散好的数ff在f的桶中++,代表出现次数+1;
优点——好写
缺点——时间复杂度比下面两种高
-
unique函数法
你不会这个函数我也救不了你,自己学吧
这个好说——包含重复元素,并且相同元素离散化后也要相同
1 const int maxn=1e5+10;
2 int a[maxn], t[maxn], b[maxn];
3 int n;
4 scanf("%d",&n);
5 for(int i=1; i<=n; i++)
6 scanf("%d",a[i]),t[i]=a[i];
7 sort(t+1,t+n+1);
8 m=unique(t+1,t+1+n)-t-1;//求出的m为不重复的元素的个数
9 for(int i=1; i<=n; i++)
10 b[i]=lower_bound(t+1,t+1+m,a[i])-t;
11 //a[i]为原来的数组,b[i]为离散化后的数组
我认为这个蛮明白得了,就显然过掉吧
优点——可处理重复元素只要一种的题目,时间复杂度肯定比map小
缺点——时间复杂度比第三种要高,且就本人刷的可怜的题量来说,实用度不如其他两种好
-
结构体+重载运算符//cmp
这个对于我来说最不好说了,因为凡是用这个来处理的题,我都用map来搞-_-||
1 struct A
2 {
3 int x, idx;
4 bool operator < (const A &rhs) const
5 {
6 return x < rhs.x;
7 }//也可以写个cmp函数排序
8 };
9 A a[MAXN];
10 int rank[MAXN];
11 int n;
12 scanf("%d",&n);
13 for(int i = 1; i <= n; ++i)
14 {
15 scanf("%d", &a[i].x);
16 a[i].idx = i;
17 }
18 //for(int i=1; i<=n; i++)
19 // printf("%d %d
",a[i].idx,a[i].x);
20 //printf("
");
21 sort(a + 1, a + n + 1);
22 //for(int i=1; i<=n; i++)
23 // printf("%d %d
",a[i].idx,a[i].x);
24 //printf("
");
25 for(int i = 1; i <= n; ++i)
26 {
27 rank[a[i].idx] = i;
28 // printf("rank[%d] = %d
",a[i].idx,i);
29 }
X是原本的数字,idx是原本数字的位置,rank是离散化后的代号
(以下为原博内容,由于蒟蒻还不会(其实就是不想学),就直接贴上了)
给你们个例子:
i 1 2 3 4
x 6 8 9 4
idx 1 2 3 4
排序后:
i 1 2 3 4 //离散化后的数字
x 4 6 8 9
idx 4 1 2 3 //数字原来的所在的位置编号
将上面两行黑体数字对应起来 即是:rank[4]=1,rank[1]=2,rank[2]=3,rank[3]=4; //rank[i]=j表示将原来在第i个位置上的数字离散化成j
so:
rank[1]=2;
rank[2]=3;
rank[3]=4;
rank[4]=1;
so: 6 8 9 4
就离散化为2,3,4,1
如果你想用原来的数字,就用排过序的结构体a[2]=6,a[3]=8,a[4]=9,a[1]=4; //a[i]=j表示排过序后现在的a数组里第i个数字的是j。j也就是第i小。
a[i]是原来的数字;
rank是离散化后的数字;
————————————————————————————后记————————————————————————————————
大概想说的,要说的,大概就是这么多。
欢迎大佬来指出错误或教我第三种是怎么搞的
以上是关于随便说说——离散化的主要内容,如果未能解决你的问题,请参考以下文章
POJ 2528 Mayor's posters 离散化+线段树