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;
 + ;
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);
    ; i <= n; ++i) {
        scanf("%d", &a[i]);
        if (a[i] <= m) {
            book[a[i]]++;
        }
    }
    ; i <= m; ++i) {
        que.push(node(book[i], i));
    }
    ;
    int get = n / m;
    ; 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, , sizeof book);
    while (!que.empty()) {
        struct node t = que.top();
        que.pop();
        book[t.id] = t.num;
    }
    ;
    int ans = inf;
    ; i <= m; ++i) {
        ans = min(ans, book[i]);
        all += book[i];
        que.push(node(book[i], i));
        GGque.push(GGnode(book[i], i));
    }
    ; 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;
    ; i <= n; ++i) {
        printf("%d ", a[i]);
    }
    return;
}

int main() {
#ifdef local
    freopen("data.txt","r",stdin);
#endif
    work();
    ;
}

感觉写的有点麻烦,

所以重写了一次。

考虑到它一定要使得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>
 + ;
int a[maxn];
int book[maxn];
set<int>pos;
void work() {
    int n, m;
    scanf("%d%d", &n, &m);
    int gold = n / m;
    ; i <= n; ++i) {
        scanf("%d", &a[i]);
        if (a[i] <= m) {
            book[a[i]]++;
        }
    }
    ; i <= n; ++i) {
        if (a[i] <= m && book[a[i]] < gold) {
            pos.insert(a[i]);
        }
    }
    ; i <= m; ++i) {
        if (book[i] < gold) pos.insert(i);
    }
//    printf("ff");
    ;
    set<int> :: iterator it = pos.begin();
    if (it != pos.end()) { //如果需要调整
        int val = *it;
        ; 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\n", gold, toChange);
    ; i <= n; ++i) {
        printf("%d ", a[i]);
    }
    return ;
}

int main() {
#ifdef local
    freopen("data.txt","r",stdin);
#endif
    work();
    ;
}

Codeforces Round #375 (Div. 2) Polycarp at the Radio 优先队列模拟题 + 贪心的更多相关文章

  1. Codeforces Round #375 (Div. 2)【A,B【模拟】,D【DFS】】

    PS_B:阿洗吧!B题卧槽数组开了250... PS_D:D题主要挂在了50*50口算得了250,数组开小,然后一开始还错了.= =哎,以后对于数据范围还是注意一点: 卧槽,这场可真二百五了... A ...

  2. Codeforces Round #234 (Div. 2) A. Inna and Choose Options 模拟题

    A. Inna and Choose Options time limit per test 1 second memory limit per test 256 megabytes input st ...

  3. Codeforces Round #368 (Div. 2) A. Brain&#39;s Photos (水题)

    Brain's Photos 题目链接: http://codeforces.com/contest/707/problem/A Description Small, but very brave, ...

  4. Codeforces Round #375 (Div. 2) C. Polycarp at the Radio 贪心

    C. Polycarp at the Radio time limit per test 2 seconds memory limit per test 256 megabytes input sta ...

  5. Codeforces Round #375 (Div. 2)

    A. The New Year: Meeting Friends 水 #include <set> #include <map> #include <stack> ...

  6. Codeforces Round #375 (Div. 2) A B C 水 模拟 贪心

    A. The New Year: Meeting Friends time limit per test 1 second memory limit per test 256 megabytes in ...

  7. Codeforces Round #375 (Div. 2) ABCDE

    A - The New Year: Meeting Friends 水 #include<iostream> #include<algorithm> using namespa ...

  8. Codeforces Round #281 (Div. 2) A. Vasya and Football 模拟

    A. Vasya and Football 题目连接: http://codeforces.com/contest/493/problem/A Description Vasya has starte ...

  9. Codeforces Round #375 (Div. 2) - D

    题目链接:http://codeforces.com/contest/723/problem/D 题意:给定n*m小大的字符矩阵.'*'表示陆地,'.'表示水域.然后湖的定义是:如果水域完全被陆地包围 ...

随机推荐

  1. java后台搭建学习计划

    1. 使用maven管理java项目 2.linux安装mysql 3.linux安装redis 4. mybatis使用demo 5. cannal使用demo 6. 用spring4开发rest应 ...

  2. getElementById() getElementsByTagName() getElementsByClassName() querySlector() querySlectorAll()区别

    1. getElementById() getElementsByTagName()  javascript原生的方法,这两个不会有兼容性问题. 2. getElementsByClassName() ...

  3. EF架构~数据分批批量提交

    回到目录 对于大数据量提交,包括插入,更新和删除,我始终不建议用EF自带的方法,因为它会增加与数据库的交互次数,一般地,EF的一个上下文在提交时会打开一个数据连接,然后把转换成的SQL语句一条一条的发 ...

  4. ZJOI day1总结

    虽然没人看,虽然滚了大粗,但还是这样勉励一下自己.. 今年大约是进队无望了. before ZJOI 感觉自己时间很充裕,与lyx大爷一起颓颓颓.. day -3 到xj. day -2 听课.感觉洲 ...

  5. 攻城狮在路上(叁)Linux(二十五)--- linux内存交换空间(swap)的构建

    swap的功能是应付物理内存不足的状况,用硬盘来暂时放置内存中的信息. 对于一般主机,物理内存都差不多够用,所以也就不会用到swap,但是对于服务器而言,当遇到大量网络请求时或许就会用到. 当swap ...

  6. web开发(二十一)之自定义拦截器的使用

    转自博客:http://blog.csdn.net/pkgk2013/article/details/51985817 拦截器的作用 拦截器,在AOP(Aspect-Oriented Programm ...

  7. 复制选中的listbox内容

    private void lt_log_MouseClick(object sender, MouseEventArgs e) { Clipboard.SetDataObject(lt_log.Sel ...

  8. WebDriver - 添加失败截图

    WebDriver失败截图可以通过两种方式实现: 1. Use WebdriverEventListener 第一步:创建自己的WebDriverEventListener 创建自己的WebDrive ...

  9. Android中ContentProvider的简单使用

    1.新建继承ContentProvider的类 package com.wangzhu.demo; import android.content.ContentProvider; import and ...

  10. Xml序列化自引用/循环引用问题1

    1.定义类 public class Student { public int ID { get; set; } public string Name { get; set; } //[XmlIgno ...