题目链接:codeforces.com/contest/1183/problem/G
题意:现在有 n n n个糖果,每个糖果有一个种类,并且每个糖果有一个你是否喜欢的标记( 0 0 0喜欢, 1 1 1不喜欢),你需要选出数目两两互不相同的各种类的糖果(可以一个类型的糖果不选完),问糖果最多可以选择多少个,在保证糖果最大的情况下,要求标号为 1 1 1的糖果最多,输出最大的糖果数和标号为 1 1 1的糖果数。
解题心得:要糖果数目最多,可以用一个优先队列按照糖果数目多的优先,当糖果数目相同时标号1糖果数量多的优先。每次从队首取出一个类型的糖果记录取出的个数,如果队列中下一个类型糖果和当前取出的个数相同,则将下一个取出,然后将其糖果数目减一,如果取出的这个种类糖果标号 1 1 1数目和总数相同时,标号 1 1 1个数种类的糖果也 − 1 -1 −1,然后重新压入队列。
#include <bits/stdc++.h>
using namespace std;
typedef complex<double> cp;
typedef long long ll;
const int maxn = 2e5+100;
const double pi = acos(-1);
struct Node {
int sum, cnt1;
bool operator < (const Node &x) const {//定义优先级
if (this->sum != x.sum)
return this->sum < x.sum;
else
return this->cnt1 < x.cnt1;
}
};
int n, t;
map <int, int> maps, map1;//分别记录一个类型糖果的数量和同类型标号为1的糖果数量
priority_queue <Node> qu;
void init() {
scanf("%d", &n);
for(int i=1;i<=n;i++) {
int type, f;
scanf("%d%d", &type, &f);
maps[type]++;
map1[type] += f;
}
map <int, int> :: iterator iter;
for(iter=maps.begin();iter!=maps.end();iter++) {//全压入队列中
Node now = {iter->second, map1[iter->first]};
qu.push(now);
}
}
int main() {
// freopen("1.in.txt", "r", stdin);
scanf("%d", &t);
while(t--) {
init();
int now = 0;//记录当前取出种类的糖果数量
int ans = 0, cnt = 0;//分别记录取出的糖果的数量和标号1的糖果数量
while (!qu.empty()) {
int sum = qu.top().sum;
int cnt1 = qu.top().cnt1;
qu.pop();
if (sum == 0) break;
if (sum != now) {
now = sum;
ans += sum;
cnt += cnt1;
} else {
if(sum == cnt1) {//全是1时只能取1
sum--;
cnt1--;
} else {
sum--;
}
qu.push({sum, cnt1});
}
}
while(!qu.empty()) qu.pop();
maps.clear();
map1.clear();
printf("%d %d\n", ans, cnt);
}
return 0;
}