比较简单的一个思维题,需要分类讨论。首先,让我们动手模拟一下:
我们需要知道id号对应的人数,然后统计出所有不规范的id,方便我们进行进一步分析。
假设我们统计出了more(多余总人数)和less(空缺总人数),按照贪心,我们应该将多余的人数和空缺的人数中和,这样就可以以最小的代价满足两边的需求。比如,6--1 4 4 4 4 4,一个4补充1,两个4转为其他id,我们需要转换1+2=3次。
根据上面的理论,我们需要考虑两个点,more和less的大小关系:
-
如果more>=less,那就按照我们上面的计算,
ans+=less; more-=less; ans+=more;
。 -
如果more<less,如 8--1 2 3 4 5 6 6 6,我们将一个6补充5,剩下四个单的相互转换,就是成了
ans+=more; less-=more; ans+=less/2
。
别担心less为奇数,因为总数为偶数,合规的是2的倍数,所以不合规的more+less的和也是偶数,所以more和less要么都是偶数,要么都是奇数。这样 less-more必定是偶数。
AC:
#include <iostream>
using namespace std;
const int N = 1e5 + 3;
int n;
int id[N]; //id
int num[N]; //num[i] 表id=i的人数
int book[N]; //标记不规范的id号 0--无此id 1--规范 2--不规范
int main()
{
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> id[i];
num[id[i]]++;
if (num[id[i]] == 2) book[id[i]] = 1;
else book[id[i]] = 2;
}
//策略:统计出多的,统计出少的
int more = 0, less = 0;
for (int i = 0; i <= n; i++)
{
if (book[i] == 2) //不规范
{
if (num[i] > 2) more += num[i] - 2;
else less += 1; //少的不规范只有缺1一种情况
}
}
/*cout << endl;
cout << "less::" << less << endl;
cout << "more::" << more << endl;*/
int ans = 0;
if (more >= less) //多的大于等于缺的,如:6--1 4 4 4 4 4,一个4补充1,两个4转为其他id
{
ans += less; //先将少的填上,变动人数就是 1*less
more -= less; //填上的是从多的里面减的
ans += more; //然后再变动多的这些
}
else //少的大于剩余的,如:8--1 2 3 4 5 6 6 6,一个6补充5,剩下四个单的相互转换
{
ans += more;
less -= more;
ans += less / 2; //因为总共是偶数,所以less到后面一定是偶数
}
cout << ans;
return 0;
}
制作不易,请给小生点个赞吧QwQ
二刷:
我真傻,第一次做的时候还用这么多个数组,其实直接用一个map就行,而且效果更佳!
//班级活动
#include <iostream>
#include <map>
using namespace std;
#define ll long long
const int N=1e5+3;
int n;
map<ll,ll>mp;
int main()
{
cin>>n;
ll more=0,less=0;
int a;
for(int i=0;i<n;i++)
{
cin>>a;
mp[a]++;
}
for(auto &it:mp)
{
if(it.second>2) more+=it.second-2;
else if(it.second==1) less++;
}
ll ans=0;
if(more>=less)
{
ans+=less;
more-=less;
ans+=more;
}
else
{
ans+=more;
less-=more;
ans+=less/2;
}
cout<<ans;
return 0;
}