专栏文章
P14361 [CSP-S 2025] 社团招新 / club(官方数据)
P14361题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mind7ad9
- 此快照首次捕获于
- 2025/12/02 00:29 3 个月前
- 此快照最后确认于
- 2025/12/02 00:29 3 个月前
怎么都用的反悔贪心……其实这题只需要一个简单的排序贪心。
思路
注意到:一个部门最多人数不超过 。
所以,最多只会有一个部门达到限制。
易得,每个成员的最小值没有任何作用。
优先取最大值减次大值较小的成员,这样当最大值所在团队满员时切换到到次大值损耗较小。
当最大值减次大值相同时,优先取其中最大值较大成员。
如此保证绝对不劣。
综上所述,只需要排序一遍,将最大值减次大值作为第一关键字,最大值作为第二关键字从大到小排序即可。
丑陋的赛时代码
CPP#include<bits/stdc++.h>
using namespace std;
int read(){
int cnt = 0, sign = 1;
char c = getchar();
while(!isdigit(c)){
if(c == '-') sign = -1;
c = getchar();
}
while(isdigit(c)){
cnt = (cnt << 1) + (cnt << 3) + (c ^ 48);
c = getchar();
}
return cnt * sign;
}//快读。
const int N = 1e5 + 10;
struct node{
int a[5];
int maxn, mid;
}mbr[N];//成员(member)。
int maxid(node x){
if(x.a[1] >= x.a[2] && x.a[1] >= x.a[3]) return 1;
if(x.a[2] >= x.a[1] && x.a[2] >= x.a[3]) return 2;
return 3;
}//找最大值位置。
int midid(node x){
if((x.a[1] <= x.a[2] && x.a[1] >= x.a[3]) || (x.a[1] <= x.a[3] && x.a[1] >= x.a[2])) return 1;
if((x.a[2] <= x.a[1] && x.a[2] >= x.a[3]) || (x.a[2] >= x.a[1] && x.a[2] <= x.a[3])) return 2;
return 3;
}//次大值位置。
bool cmp(node x, node y){
return (x.a[x.maxn] - x.a[x.mid] == y.a[y.maxn] - y.a[y.mid]) ? (x.a[x.maxn] > y.a[y.maxn]) : (x.a[x.maxn] - x.a[x.mid] > y.a[y.maxn] - y.a[y.mid]);
}//核心代码。
int main(){
// freopen("club.in", "r", stdin);
// freopen("club.out", "w", stdout);
int T = read();
while(T--){
int cnt[5];
memset(cnt, 0, sizeof(cnt));//记得初始化。
int n = read();
for(int i = 1; i <= n; i++){
int a = read(), b = read(), c = read();
mbr[i].a[1] = a;
mbr[i].a[2] = b;
mbr[i].a[3] = c;
mbr[i].maxn = maxid(mbr[i]);
mbr[i].mid = midid(mbr[i]);
}
sort(mbr + 1, mbr + n + 1, cmp);//排序。
int ans = 0;
for(int i = 1; i <= n; i++){
if(cnt[mbr[i].maxn] == n / 2){
ans += mbr[i].a[mbr[i].mid];
cnt[mbr[i].mid]++;
}else{
ans += mbr[i].a[mbr[i].maxn];
cnt[mbr[i].maxn]++;
}//优先放进最大值所在桶,当前最大值所在桶满了之后取次大值。
}
printf("%d\n", ans);
}
return 0;
}
已通过官方数据。
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...