• [模板]离散化


    离散化基于这样一种思想:当想要存储的数据的量较小,而数值较大,并且操作对象是数值时,使用数值的排名来代表数值进行操作.

    与哈希算法很相似,不过这种算法一定不会发生冲突,但是预处理复杂度为O(NlogN),单次查询的复杂度是O(logN).

     给出的数在32位有符号整数范围内.

    如果每当一个数字第一次出现时,将其记录为已出现,当下一次出现时就可以忽略它了.

    为了进行这样的记录,使用排名代表数字,使得每个数字(重复视为同一个数字)与其排名形成一一对应关系.使用discrete函数构建这种关系:

    // 假设给定的ind个数据已经复制到了dis数组中
    void discrete() {    // O(NlogN)
        sort(dis + 1, dis + 1 + ind);
        ind = unique(dis + 1, dis + 1 + ind) - dis - 1;    // unique的复杂度是O(N)
    }

    现在dis数组中就有了排序并去重后的数字,排名为i的数字为dis[i]的值.之后处理dis[i]时用i代替之.

    例如,读取到一个数字123456789,使用query函数获取其排名:

    // O(logN)
    int query(int x) { return lower_bound(dis + 1, dis + 1 + ind, x) - dis; }

    假设query(123456789)返回了5,那么检查排名为5的数字是否已经出现过了(used[5] == true),如果没有出现过就输出dis[5]并标记为已出现,否则直接读取下一个数字.

    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    #define SIZE 50000
    
    int s[SIZE + 10], dis[SIZE + 10], idx;
    bool used[SIZE + 10];
    
    inline int read() {
        char ch = getchar();
        int x = 0, f = 1;
        while (ch > '9' || ch < '0') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9') {
            x = x * 10 + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    void discrete() {
        sort(dis + 1, dis + 1 + idx);
        idx = unique(dis + 1, dis + 1 + idx) - dis - 1;
    }
    int query(int x) { return lower_bound(dis + 1, dis + 1 + idx, x) - dis; }
    
    void solve() {
        int n = read();
        idx = 0;
        memset(used, 0, sizeof(bool) * (n + 1));
        for (int i = 1; i <= n; i++) {
            s[i] = read();
            dis[++idx] = s[i];
        }
        discrete();
    
        for (int i = 1; i <= n; i++) {
            int ns = query(s[i]);
            if (!used[ns]) {
                printf("%d ", s[i]);
                used[ns] = true;
            }
        }
        puts("");
    }
    
    int main() {
        int t;
        t = read();
        while (t--) solve();
    
        return 0;
    }
    P4305
  • 相关阅读:
    区块链的入门
    数组元素查找(查找指定元素第一次在数组中出现的索引)
    数组查表法之根据键盘录入索引,查找对应星期
    数组元素反转
    数组获取最大值
    数组的遍历
    数组操作的两个常见小问题越界和空指针
    方法重载练习比较数据是否相等
    方法之根据键盘录入的数据输出对应的乘法表
    方法之根据键盘录入的行数和列数,在控制台输出星形
  • 原文地址:https://www.cnblogs.com/Gaomez/p/14255620.html
Copyright © 2020-2023  润新知