题解: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;
}
感谢阅读~
本文来自博客园,作者:Circle_Table,转载请注明原文链接:https://www.cnblogs.com/Circle-Table/articles/19177413

浙公网安备 33010602011771号