S组第一题
思路
首先如果没那个不能超过一半的限制,肯定每个人都选那个最优的。
如果加上了那个限制呢?那么有可能会出现有个社团过于火爆。
如何去应对这个情况呢?
不知道大家有没有知道清华那边有个叫“调济”的模式,就是给那个分低的从人超了的专业挪到比较冷清的专业。
我们这里也要用类似于这个模式的思维。将超了的一些人都给他调到那个比较冷清的社团。
但是我们这里的第一关键字,不是分数。
那是什么呢?我们知道如果一个人去调专业的话,他对答案的贡献就会减少一个(之前的社团喜欢度-调到的社团的喜欢度)。举个例子,如果这个人之前的社团是
为了最优,我们给他调到的社团一定是他第二喜欢的(因为第一次选的那个应该是最喜欢的)。
其次,调完之后会不会出现超的情况呢?显然不会。因为最火爆的那个社团应该剩下
于是我们考虑预处理一个每个人(第一的社团喜欢度-第二的社团的喜欢度),到时候在超的那里面以这个为关键字进行一个排序,找到那些对答案影响最小的,只能委屈一下他们啦。
于是就可以写代码了。
#include <bits/stdc++.h>
using namespace std;
int n, a[114514][5], to[114514], to_a[114514], to_b[114514], to_c[114514];
bool cmp (int a, int b)
{
return to[a] > to[b];
}
void mian()
{
int cnta = 0, cntb = 0, cntc = 0, maxx = 0;
cin >> n;
int ans = 0;
for (int i = 1; i <= n; i ++)
{
cin >> a[i][1] >> a[i][2] >> a[i][3];
int maxx = max (a[i][1], max (a[i][2], a[i][3]));
int cmax = a[i][1] + a[i][2] + a[i][3] - maxx - min (min (a[i][1], a[i][2]), a[i][3]);
if (maxx == a[i][1]) to_a[++cnta] = i;
else if (maxx == a[i][2]) to_b[++cntb] = i;
else to_c[++cntc] = i;
to[i] = cmax - maxx;
ans += maxx;
}
sort (to_a + 1, to_a + cnta + 1, cmp);
sort (to_b + 1, to_b + cntb + 1, cmp);
sort (to_c + 1, to_c + cntc + 1, cmp);
if (cnta > n / 2)
{
for (int i = 1; i <= cnta - n / 2; i ++) ans += to[to_a[i]];
}
else if (cntb > n / 2)
{
for (int i = 1; i <= cntb - n / 2; i ++) ans += to[to_b[i]];
}
else if (cntc > n / 2)
{
for (int i = 1; i <= cntc - n / 2; i ++) ans += to[to_c[i]];
}
cout << ans << endl;
}
int main()
{
int T;
cin >> T;
while (T --) mian();
}