zoukankan      html  css  js  c++  java
  • Codeforces Round #375 (Div. 2) Polycarp at the Radio 优先队列模拟题 + 贪心

    http://codeforces.com/contest/723/problem/C

    题目是给出一个序列

    a[i]表示第i个歌曲是第a[i]个人演唱,现在选出前m个人,记b[j]表示第j个人演唱歌曲的数量,

    现在你可以改变a[]这个数组,使得前m个人的演唱歌曲的数量的最小值最大。

    很明显对于前m个人,每个人唱了多少首是很容易统计出来的,只需要对<=m的人进行统计即可,不用统计>m的,这样的话数组只需开到2000即可。

    对于后面的人,可以改变,优先改变前m个人中演唱歌曲最小的那个,这个可以用优先队列维护。

    然后如果前m个人本来分配不均匀,那么最小值的最大值得不到最大化。

    要对前m个人均匀一下,这个我用了两个优先队列去做,因为思路就是把最大的分一次给最小的,这样的最优的。

    hack点:注意到ans最多也只是n / m。就相当于把n分成m分,如果前m个人的答案已经是n / m,后面的人就不需要变化的,不然的话改变数量变大了,会错误。好像wa7就是这个坑。

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    
    #include <iostream>
    #include <sstream>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    int n, m;
    const int maxn = 2000 + 20;
    int book[maxn];
    int a[maxn];
    struct node {
        int num;
        int id;
        bool operator < (const struct node &rhs) const {
            return num > rhs.num;
        }
        node(int aa, int bb) : num(aa), id(bb) {}
    };
    struct GGnode {
        int num;
        int id;
        bool operator < (const struct GGnode &rhs) const {
            return num < rhs.num;
        }
        GGnode(int aa, int bb) : num(aa), id(bb) {}
    };
    priority_queue<struct node>que;
    priority_queue<struct GGnode>GGque;
    vector<int>pos[maxn];
    void work() {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; ++i) {
            scanf("%d", &a[i]);
            if (a[i] <= m) {
                book[a[i]]++;
            }
        }
        for (int i = 1; i <= m; ++i) {
            que.push(node(book[i], i));
        }
        int tochange = 0;
        int get = n / m;
        for (int i = 1; i <= n; ++i) {
            if (a[i] <= m) continue;
            struct node t = que.top();
            if (t.num == get) break;
            que.pop();
            a[i] = t.id;
            t.num++;
            que.push(t);
            tochange++;
        }
        memset(book, 0, sizeof book);
        while (!que.empty()) {
            struct node t = que.top();
            que.pop();
            book[t.id] = t.num;
        }
        int all = 0;
        int ans = inf;
        for (int i = 1; i <= m; ++i) {
            ans = min(ans, book[i]);
            all += book[i];
            que.push(node(book[i], i));
            GGque.push(GGnode(book[i], i));
        }
        for (int i = 1; i <= n; ++i) {
            if (a[i] <= m) {
                pos[a[i]].push_back(i);
            }
        }
        int gold = all / m;
        if (ans != gold) {
            while (true) {
                struct node tt = que.top();
                que.pop();
                struct GGnode GGtt = GGque.top();
                GGque.pop();
                if (book[tt.id] == gold) break;
    
                book[tt.id]++;
                book[GGtt.id]--;
                int tpos = pos[GGtt.id].back();
                pos[GGtt.id].pop_back();
                a[tpos] = tt.id;
    
                tt.num = book[tt.id];
                GGtt.num = book[GGtt.id];
    
                que.push(tt);
                GGque.push(GGtt);
                tochange++;
            }
        }
        ans = gold;
        cout << ans << " " << tochange << endl;
        for (int i = 1; i <= n; ++i) {
            printf("%d ", a[i]);
        }
        return;
    }
    
    int main() {
    #ifdef local
        freopen("data.txt","r",stdin);
    #endif
        work();
        return 0;
    }
    View Code

    感觉写的有点麻烦,

    所以重写了一次。

    考虑到它一定要使得b[j]数组中的最小值最大,而这个最大值,必然是n / m的。所以,直接把1---m中数量小于n / m的统计起来,用其他去变即可。

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    
    #include <iostream>
    #include <sstream>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    const int maxn = 2000 + 20;
    int a[maxn];
    int book[maxn];
    set<int>pos;
    void work() {
        int n, m;
        scanf("%d%d", &n, &m);
        int gold = n / m;
        for (int i = 1; i <= n; ++i) {
            scanf("%d", &a[i]);
            if (a[i] <= m) {
                book[a[i]]++;
            }
        }
        for (int i = 1; i <= n; ++i) {
            if (a[i] <= m && book[a[i]] < gold) {
                pos.insert(a[i]);
            }
        }
        for (int i = 1; i <= m; ++i) {
            if (book[i] < gold) pos.insert(i);
        }
    //    printf("ff");
        int toChange = 0;
        set<int> :: iterator it = pos.begin();
        if (it != pos.end()) { //如果需要调整
            int val = *it;
            for (int i = 1; i <= n; ++i) {
                if (a[i] > m) {
                    book[val]++;
                    a[i] = val;
                    toChange++;
                } else {
                    if (pos.find(a[i]) != pos.end()) continue;
                    if (book[a[i]] == gold) continue;
                    book[a[i]]--;
                    book[val]++;
                    a[i] = val;
                    toChange++;
                }
                if (book[val] == gold) {
                    it++;
                    if (it == pos.end()) break;
                    val = *it;
                }
            }
        }
        printf("%d %d
    ", gold, toChange);
        for (int i = 1; i <= n; ++i) {
            printf("%d ", a[i]);
        }
        return ;
    }
    
    int main() {
    #ifdef local
        freopen("data.txt","r",stdin);
    #endif
        work();
        return 0;
    }
    View Code
  • 相关阅读:
    Java 老兵不死,Kotlin 蓄势待发
    程序员写代码时戴着耳机,在听什么?
    推荐 7 个提升前端编程效率的 VSCode 插件
    去掉烦人的 !=null
    透析!软件开发未来 10 年的 8 个趋势
    10月01日总结
    09月29日总结
    09月28日总结
    09月27日总结
    09月26日总结
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/5929776.html
Copyright © 2011-2022 走看看