STL例子:修订间差异

来自三三百科
跳转到导航 跳转到搜索
33DAI留言 | 贡献
33DAI留言 | 贡献
第450行: 第450行:


===nth_element===
===nth_element===
时间复杂度 <math>O(n)</math>,快排每次只排序 k 所在的那一部分。


<syntaxhighlight lang="cpp" line>
<syntaxhighlight lang="cpp" line>

2026年2月8日 (日) 09:42的版本

明明的随机数

排序后枚举

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1000000;
const int MAXAI = 100000;
int n;
int a[MAXN + 5];
void work()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    sort(a + 1, a + n + 1);
    int cnt = 1;
    for (int i = 2; i <= n; i++)
        if (a[i] != a[i - 1])
            cnt++;
    cout << cnt << "\n";
    cout << a[1] << " ";
    for (int i = 2; i <= n; i++)
        if (a[i] != a[i - 1])
            cout << a[i] << " ";
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    work();
    return 0;
}

使用 unique 去重

int n;
int a[MAXN + 5];
void work()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    sort(a + 1, a + n + 1);
    int nn = unique(a + 1, a + n + 1) - a - 1;
    cout << nn << "\n";
    for (int i = 1; i <= nn; i++)
        cout << a[i] << " ";
}

vector 排序后 unique 去重

int n;
vector<int> a;
void work()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        int x;
        cin >> x;
        a.push_back(x);
    }
    sort(a.begin(), a.end());
    int nn = unique(a.begin(), a.end()) - a.begin();
    cout << nn << "\n";
    for (int i = 0; i <= nn - 1; i++)
        cout << a[i] << " ";
}

vector 排序后迭代器枚举

int n;
vector<int> a;
void work()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        int x;
        cin >> x;
        a.push_back(x);
    }
    sort(a.begin(), a.end());
    // [a.begin(), R)
    vector<int>::iterator R = unique(a.begin(), a.end());
    cout << (R - a.begin()) << "\n";
    for (auto it = a.begin(); it != R; it++)
        cout << (*it) << " ";
}

计数排序

int n;
int a[MAXN + 5];
int cnt[MAXAI + 5];
void work()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
        
    int ans = 0;
    for (int i = 1; i <= n; i++)
    {
        cnt[a[i]]++;
        if (cnt[a[i]] == 1)
            ans++;
    }
    cout << ans << "\n";
    for (int i = 1; i <= MAXAI; i++)
        if (cnt[i] >= 1)
            cout << i << " ";
}

bitset 判断每个数是否出现

int n;
bitset<MAXAI + 1> cnt;
void work()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        int x;
        cin >> x;
        cnt.set(x);
    }
    cout << cnt.count() << "\n";
    for (int i = 1; i <= MAXAI; i++)
        if (cnt[i])
            cout << i << " ";
}

合并果子

multiset

#include <bits/stdc++.h>
using namespace std;
int n;
int a[30000 + 5];
multiset<int> s;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        s.insert(a[i]);
    }
    long long ans = 0;
    while (s.size() > 1)
    {
        int a = *s.begin();
        // 如果erase(a),会删除所有 a,所以只删除迭代器的值
        s.erase(s.begin());
        int b = *s.begin();
        s.erase(s.begin());
        ans += (a + b);
        s.insert(a + b);
    }
    cout << ans;
    return 0;
}

map

#include <bits/stdc++.h>
using namespace std;
int n;
int a[30000 + 5];
map<int, int> m;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        m[a[i]]++;
    }
    long long ans = 0;
    for (int i = 1; i <= n - 1; i++)
    {
        auto it = m.begin();
        // 取 a
        int a = (*it).first;
        (*it).second--;
        if ((*it).second == 0)
            m.erase(it);
        // 取 b
        it = m.begin();
        int b = it->first;
        it->second--;
        if (it->second == 0)
            m.erase(it);
        // 合并
        ans += (a + b);
        m[a + b]++;
    }
    cout << ans;
    return 0;
}

priority_queue

传相反数实现小根堆

#include <bits/stdc++.h>
using namespace std;
int n;
int a[30000 + 5];
// q.push(x); // 把 x 放入优先队列(O(logSize))
// q.top();   // 优先队列中最大的元素(O(1))
// q.pop();   // 弹出(删除)最大的元素(O(logSize))
priority_queue<int> q;
int main()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    // 都放到优先队列里
    for (int i = 1; i <= n; i++)
        q.push(-a[i]); // 存相反数,来实现最小堆
    int ans = 0;
    for (int i = 1; i <= n - 1; i++)
    {
        int x = -q.top();
        q.pop();
        int y = -q.top();
        q.pop();
        ans += x + y;
        q.push(-(x + y));
    }
    cout << ans;
    return 0;
}

重载运算符的优先队列

#include <bits/stdc++.h>
using namespace std;
int n;
struct Guozi
{
    int daxiao;
};
Guozi a[30000 + 5];
// 把小于号用大于的规则定义,这样取出来的最大值就会使daxiao最小的
bool operator<(const Guozi &a, const Guozi &b)
{
    return a.daxiao > b.daxiao;
}
// q.push(x); // 把 x 放入优先队列(O(logSize))
// q.top();   // 优先队列中最大的元素(O(1))
// q.pop();   // 弹出(删除)最大的元素(O(logSize))
priority_queue<Guozi> q;
int main()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> a[i].daxiao;
    // 都放到优先队列里
    for (int i = 1; i <= n; i++)
        q.push(a[i]);
    int ans = 0;
    for (int i = 1; i <= n - 1; i++)
    {
        int x = q.top().daxiao;
        q.pop();
        int y = q.top().daxiao;
        q.pop();
        ans += x + y;
        q.push((Guozi){x + y});
    }
    cout << ans;
    return 0;
}

自己实现小根堆

#include <bits/stdc++.h>
using namespace std;
int n;
const int MAXN = 30000;
// 小根堆(越小越优先的优先队列)
struct PQ
{
    int tot;
    int t[MAXN + 5];
    void clear()
    {
        tot = 0;
    }
    int size()
    {
        return tot;
    }
    bool empty()
    {
        return tot == 0;
    }
    int top()
    {
        // 可以自己检测非法
        return t[1];
    }
    void push(int x)
    {
        tot++;
        t[tot] = x;
        int now = tot;
        // 不是根节点,并且父节点比自己大的时候往上走
        while (now != 1 && t[now / 2] > t[now])
        {
            swap(t[now / 2], t[now]);
            now /= 2;
        }
    }
    void pop()
    {
        swap(t[1], t[tot]);
        tot--;
        // 从根节点开始维护到合适位置
        int now = 1;
        while (1)
        {
            // 没有子节点
            if (now * 2 > tot)
                break;
            // 只有左子节点
            else if (now * 2 + 1 > tot)
            {
                if (t[now * 2] < t[now])
                {
                    swap(t[now * 2], t[now]);
                    now = now * 2;
                }
                else
                    break;
            }
            // 左右子节点都有
            else
            {
                // 自己最小
                if (t[now] <= t[now * 2] && t[now] <= t[now * 2 + 1])
                    break;
                // 左边最小
                else if (t[now * 2] <= t[now * 2 + 1])
                {
                    swap(t[now * 2], t[now]);
                    now = now * 2;
                }
                else
                {
                    swap(t[now * 2 + 1], t[now]);
                    now = now * 2 + 1;
                }
            }
        }
    }
};
PQ q;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> n;
    q.clear();
    for (int i = 1; i <= n; i++)
    {
        int x;
        cin >> x;
        q.push(x);
    }
    long long ans = 0;
    while (q.size() > 1)
    {
        int a = q.top();
        q.pop();
        int b = q.top();
        q.pop();
        // 合并
        ans += (a + b);
        q.push(a + b);
    }
    cout << ans;
    return 0;
}

全排列问题

next_permutation

如果已经是最后一个排列了,执行之后会变为第一个排列,并返回假,否则返回真。

#include <bits/stdc++.h>
using namespace std;
int n;
int a[10];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> n;
    for (int i = 1; i <= n; i++)
        a[i] = i;
    while (1)
    {
        for (int i = 1; i <= n; i++)
            cout << "    " << a[i];
        cout << "\n";
        if (!next_permutation(a + 1, a + n + 1))
            break;
    }
    return 0;
}

求第 k 大数

nth_element

时间复杂度 [math]\displaystyle{ O(n) }[/math],快排每次只排序 k 所在的那一部分。

#include <bits/stdc++.h>
using namespace std;
int n, k;
int a[1000000 + 5];
bool cmp(int a, int b)
{
    return a > b;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> n >> k;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    nth_element(a + 1, a + k, a + n + 1, cmp);
    cout << a[k];
    return 0;
}

部落卫队