题解:P12881 [蓝桥杯 2025 国 C] 宗门大比

题目传送门

题意简述:给定的 \(n\) 个正整数 \(a_1,a_2,⋯,a_n\) 中,进行 \(m\) 此操作,每次可以将不超过它们最大值的任意一个整数的值减一,然后令 \(a_k\) 的排名尽可能靠前。

然后观察样例。样例中小蓝的功力值为 \(5\) 点,由于存在 \(a_4=6\) 是最大值,最大值无论如何切磋都不会输,因此最后小蓝只能排第二。

可以看出,最大值是不会变的,所以如果小蓝就是那个最大值,即当 \(a_k=a_{max}\) 时直接输出他左边与他同功力的人数即可(至于为什么不是 \(1\) 在后文有提到)。
若小蓝不是最大值,就让最大值和比小蓝强的进行切磋,从而使得小蓝的排名尽可能靠前。这个过程当然优先选择功力值与小蓝尽可能接近的,所以计算每一个人直到小蓝成为第二名或者 \(m=0\) 时停止。


然而以上是在洛谷评测judging的时候写的,但是 judging 完后才发现事情不对劲,因为细节太多了,错了好多次之后在 ImposterAnYu 大佬的帮助下通过了(另还感谢大佬 lrqcs 提供 hack 数据),拜谢。
我也就总结一下这个题的细节吧。
第一,做的时候要多斟酌一下什么时候算小蓝自己,什么时候不算的情况;
第二,在小蓝左边的与他同功力的最后会排在其前面,所以在他左边的弟子就需要多消耗一次切磋才可以使得小蓝超过他;
第三,小蓝功力最高时,说不定有与他同功力的,因此不是直接输出 \(1\) 而应该输出他左边与他同功力的人数,右边的当然是不用管的。

还有别的小细节,也就只能说这题细节真多了。

代码如下

#include<bits/stdc++.h>
#define ios ios::sync_with_stdio,cin.tie(0),cout.tie(0)
using namespace std;
int n,m,k,x;
int a[500005];
int ans=1;//排名包括他自己
vector<int> v;//存储比小蓝功力高的弟子 
int main() {
	ios;cin>>n>>m>>k;
	int maxn=0;
	for(int i=1;i<=n;i++){	
		cin>>a[i];
		maxn=max(maxn,a[i]);//记录最大功力
	}
	x=a[k]; //小蓝的功力值
	
	//收集功力大于等于小蓝的弟子
	//并计算将其将至低于小蓝的切磋次数 
	for(int i=1;i<=n;i++){
		if(i==k)continue;//已经算过自己了,这回就别把自己算进去了
		if(a[i]==maxn&&(x!=maxn||i<k)){//功力最大的弟子无法被减功力
			ans++;//但有个特殊情况:小蓝功力最大且右边有同功力的人时,不用算答案
			continue;
		}
		if(i<k)a[i]++;//如果在小蓝左边则要多减一次 
		if(a[i]>x)v.push_back(a[i]);
	}
	
	//如果小蓝功力最高,直接输出和他同功力的人数
	if(v.empty()){
		cout<<ans;
		return 0;
	}
	//将功力比小蓝高的排序 
	sort(v.begin(),v.end());//从小到大排,因为要贪心,先把小的减到比小蓝小
	//这样能尽可能多的把其他弟子的功力降到排在小蓝后面
	//求能将多少人功力值降到比小蓝低,当然不用算最大值 
	//此时是相同即可因为在前面已经a[i]++了 
	ans+=v.size();
	for(int i=0;i<v.size();i++){
		if(m<v[i]-x){//k是下标,x才是小蓝的功力……
			break;
		}
		m-=v[i]-x;
		ans--;
	}
	cout<<ans;
}

感谢阅读~

posted @ 2025-10-30 16:14  Circle_Table  阅读(1)  评论(0)    收藏  举报