cf 570 div3 D题解

原题
This problem is actually a subproblem of problem G from the same contest.

There are n candies in a candy box. The type of the i-th candy is ai (1≤ai≤n).

You have to prepare a gift using some of these candies with the following restriction: the numbers of candies of each type presented in a gift should be all distinct (i. e. for example, a gift having two candies of type 1 and two candies of type 2 is bad).

It is possible that multiple types of candies are completely absent from the gift. It is also possible that not all candies of some types will be taken to a gift.

Your task is to find out the maximum possible size of the single gift you can prepare using the candies you have.

You have to answer q independent queries.

If you are Python programmer, consider using PyPy instead of Python when you submit your code.

Input
The first line of the input contains one integer q (1≤q≤2⋅105) — the number of queries. Each query is represented by two lines.

The first line of each query contains one integer n (1≤n≤2⋅105) — the number of candies.

The second line of each query contains n integers a1,a2,…,an (1≤ai≤n), where ai is the type of the i-th candy in the box.

It is guaranteed that the sum of n over all queries does not exceed 2⋅105.

Output
For each query print one integer — the maximum possible size of the single gift you can compose using candies you got in this query with the restriction described in the problem statement.

题意
若干个种类的糖果,不同的数字代表不同的糖果,现在要你在糖果中选取,不同种类的糖果的数目是要不同的,问应该怎么选才能使选的糖果的数目最多

题解
首先不难发现,给了众多品牌的糖果数目,那么就要先统计不同类的糖果分别有多少个,新开一个同样大小的数组来将不同种糖果的数目进行保存。

之后,因为要选的糖果的数目不同而且要尽可能的大,那么我们很容易想到贪心的思想,那么我们就对储存糖果不同种类数目的数组进行降序排序。

排序后我们可以发现,显然,第一个数是一定要取的,因为这个数是最大的,那么问题来了,如果后面有数和它一样大,应该怎么处理。这里我们首先很容易想到开一个标记数组,如果发现有重复的值将他标记一下,然后减一即可,直到选取到没有出现过的值。但这样操作显然比较麻烦,那么我们不妨换一种思路:如果后面的这个数与前面的数不相等,那么后面这个数必然可以取到(降序排列),所以我们只需要考虑相等的情况,如果相等,那么能取到的最大的值必然是上一个数减一,这时候注意,不能直接将后面这个数减一处理,因为可能出现多个相同的数相连的情况,但我们要想清楚,最差的情况,后面的数也不会比前面的数大超过1,因为降序排列过,而且前面的数最多减一。所以,一旦出现后面的数比前面的数大,说明前面做过处理,而处理就是将后面的数变成前面的数减一

代码如下

#include <bits/stdc++.h>
using namespace std;
int a[200005];
int b[200005];
bool cmp(int a,int b)
{
    return a>b;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);//加速
    int n,i,j,k,t,q;
    long long s;
    cin>>q;
    while(q--){
        cin>>n;
        for(i=0;i<=n;i++)
            a[i]=0,b[i]=0;//用多少,初始化多少,直接莽夫memset的话会超时
        for(i=0;i<n;i++){
            cin>>a[i];
        }
        for(i=0;i<n;i++)
            b[a[i]-1]++;//这里要减一,因为数组是从0开始的
        sort(b,b+n,cmp);
        s=b[0];
        for(i=1;i<n;i++){
            if(b[i]>b[i-1]-1){
                b[i]=b[i-1]-1;//更新后面的值
            }
            if(b[i]>0)
            s=s+b[i];
        }
        cout<<s<<endl;
    }
    return 0;
}

完结!
(太机智了!!)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值