CSP-S 2025 T1 [社团招新]解题报告

OI生涯之殇

场上被这道题硬控2h,最后只能打完性质分和暴力分仓皇离场
我的OI生涯的最后一场比赛就这么以一种极度恶心的方式落幕了

切入

我们首先要注意到$ n\geq 10^5$,这意味着 \(dp\)是不可行的,因此,我们要考虑贪心

解决

根据约束条件$ cnt_i \leq n/2$我们可以想到先贪心地取每个组的最大值,如果该方案合法,就输出结果
那如果不合法呢?
此时我们就要考虑反悔
可以使用优先队列存每组次大值与最大值的差值,这样就可以在超出 \(n/2\)的组上对原有的 \(ans\)进行一个减法,直到该组合法
由于约束条件为 \(cnt_i \leq n/2\),我们可以推断出最多只有一个组是不合法的,故而能够证明这样的反悔是合法的
为什么考场上我就没有想出来呢......

AC Code
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define endll " "
#define fre(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
#define pii pair<int,int>
#define pb push_back
#define eb emplace_back
#define it inline int
#define iv inline void
#define ib inline bool
#define sakura_no_uta return 0
#pragma GCC optimize(0)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
using namespace std;
const int MAXN=500050;
const int INF=0x3f3f3f3f3f3f3f3f;
const int MOD=998244353;
it gcd(int x,int y) {return y==0?x:gcd(y,x%y);}
it lcm(int x,int y) {return y/gcd(x,y)*x;}
it max(int x,int y) {return x>y?x:y;}
it min(int x,int y) {return x<y?x:y;}
it ksm(int x,int m,int mod)
{
	int res=1,bas=x%mod;
	while(m)
	{
		if(m&1)
			res=(res*bas)%mod;
		bas=(bas*bas)%mod;
		m >>= 1;
	}
	return res;
}
int n,m,l,r,u,v,w,cnt,tot,ans,cnt1,cnt2,cnt3,lim,T;
struct lane
{
	int a,b,c,maxn;
}t[MAXN];
priority_queue<int> f,g,h;
signed main()
{
	fre("club");
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin >> T;
	while(T--)
	{
		cin >> n;
		memset(t,0,sizeof(t));
		ans=0;
		cnt1=0;
		cnt2=0;
		cnt3=0;
		lim=n/2;
		for(int i=1;i<=n;i++)
		{
			cin >> t[i].a >> t[i].b >> t[i].c;
			t[i].maxn=max(t[i].a,max(t[i].b,t[i].c));
			if(t[i].a==t[i].maxn)
			{
				cnt1++;
				ans+=t[i].maxn;
				f.push(max(t[i].b-t[i].a,t[i].c-t[i].a));
			}
			else
			{
				if(t[i].b==t[i].maxn)
				{
					cnt2++;
					ans+=t[i].maxn;
					g.push(max(t[i].a-t[i].b,t[i].a-t[i].b));
				}
				else
				{
					cnt3++;
					ans+=t[i].maxn;
					h.push(max(t[i].a-t[i].c,t[i].b-t[i].c));
				}
			}
		}
		while(cnt1>lim)
		{
			ans+=f.top();
			f.pop();
			cnt1--;
		}
		while(cnt2>lim)
		{
			ans+=g.top();
			g.pop();
			cnt2--;
		}
		while(cnt3>lim)
		{
			ans+=h.top();
			h.pop();
			cnt3--;
		}
		while(!f.empty())
			f.pop();
		while(!g.empty())
			g.pop();
		while(!h.empty())
			h.pop();
		cout<<ans<<endl;
	}
	sakura_no_uta;
}
posted @ 2025-11-05 22:01  KLaneX  阅读(3)  评论(0)    收藏  举报