题解:

题目难度:中等

知识点:数学逻辑、动态数组、map

首先要明确:当小朋友所报数字相同时,小朋友可互相认为对方和自己颜色相同;当小朋友所报数字不相同时,那么双方颜色一定不相同。

方法一:

步骤一:首先将小朋友所报数字放入动态数组v中,记录小朋友人数res初始化值为0。

步骤二:构造map依次对数组v中的数字进行判断,判断方法如下:

1.判断该数字v[i]作为键值是否已经存入map中,若没有存入,将其放入,并将m(v[i])值设置为1(该值表示到现在为止该数字v[i]出现的次数,由于此处为初次出现,所以将其值设置为1);小朋友人数res值加上v[i]+1。(v[i]表示有几个小朋友和自己相同,那么其值可以理解为拿到该颜色糖果的小朋友数目)。

2.如果该数字v[i]已经出现,判断m[v[i]]的值是否大于v[i]+1,如果值小于v[i]+1,那么让m[v[i]]的值加一即可。

3.如果m[v[i]]的值大于v[i]+1时(表明之后出现该数字的小朋友要重新组成一队,如:数字2一共出现5次,那么有两队),m[v[i]]重新设置为1,res的值加上v[i]+1。

步骤三:输出res

【注】:数字2一共出现5次,其例子运算过程如下表。通过该例子很容易理解有多种不同值输入的运算情况。其中需要注意:每当m[v[i]]的值设置为1时,小朋友数目res添加v[i]+1,而不是每当m[v[i]]的值等于v[i]+1时小朋友数目增加。因为最后一对可能不能达到v[i]+1,这是最后一对我们需要填满。(同该情况:只有一个小朋友报数为3,那么根据该信息至少存在4个小朋友)

图片说明

#include<iostream>
#include<vector>
#include<map>
using namespace std;
int main()
{
    vector<int> v;
    int t;
    //将输入放到Vector中 
    while(cin>>t)
       v.push_back(t);

    map<int,int> m;  
    int res = 0;
    //遍历Vector的值 
    for(int i = 0;i<v.size();i++) {

        if(m.find(v[i]) == m.end()) 
        {
            m[v[i]] = 1;
            res+=v[i]+1;
        }
        else if(m[v[i]]<=v[i])
        {
            m[v[i]]++;
        }
        else  
        {
            m[v[i]] = 1;
            res+=v[i]+1;
        }
    }
    cout<<res<<endl;
    return 0;
}

方法二

上述方法一是对依次输入数据进行判断,方法二直接将输入保存在map中,每个键值(输入值加一)对应的值为该数出现的次数。如输入:1 1 3,那么m[2]=2,m[4]=1。可以简单理解为有两种抱团方式,一种是两个人抱团,一种是4个人抱团。现在可以两个人抱团的有2个人,4个人抱团的有一个人。那么,这两个人直接抱团,4个人抱团的现在只有一个人,那么肯定至少还需要3人组成一个4人团。

从上分析可得:遍历map,我们将键值赋值给变量J,所对应的值赋给k。那么可以理解为:抱团方式为J个人抱团,需要抱团的人数为k个。k/j表示可以直接抱多少个团,那么人数等于团数乘上每个团的人数,即(k/j)*j;如果不能整除,那么就会有人剩下没有加入组团,需要给他们添加人到一个团需要的数量j。

#include<iostream>
#include<vector>
#include<map>
using namespace std;
int main()
{
    map<int,int> m;  
    map<int,int>::iterator iter;
    int t;
    while(cin>>t)
       m[t+1]++;
    int count=0;
    for(iter=m.begin();iter!=m.end();iter++){
        int j,k;
        j=iter->first;
        k=iter->second;
        if(k%j==0) count+=(k/j)*j;
        else count+=(k/j)*j + j;
    }
    cout<<count;
    return 0;
}