题意
题意:给我们一个长度为n的数组a和我们拥有的时间m,一共有n+1个人,我们每一个人都要和剩下的n个人打比赛。首先出现在数组里的不管数本身的大小,如果 i > j i > j i>j那就说明第i个人赢了。然后我们考虑最后一个人,他现在有m的准备时间,如果想要赢下第i个人的话,那么我们就要准备 a i a_i ai的时间,问我们最后一个人他的最高排名是多少。
思路
思路:首先呢我们可以想到,数组中的人的胜场数是已经确定的分别是 0 , 1 , 2 , 3 , . . . , n − 1 0,1,2,3,...,n-1 0,1,2,3,...,n−1局。
我们考虑贪心,问我们怎么打是排名最高的,也就是胜场数最多,贪心策略就是我们排一下序,从最小的开始打,那么现在假设我们可以得到我们赢了res场。正常的话我们就输出 n − r e s + 1 n - res + 1 n−res+1就可以了。
好了,现在我们来考虑一种特殊的情况,假设给我们一组数据是 5 , 9 5 ,9 5,9 ,然后a数组内是 1 , 2 , 3 , 4 , 5 1,2,3,4,5 1,2,3,4,5,好经过我们刚才的运算我们可以打败前3个人,赢了三场,我们还有两个人没打败,那么我们的答案就是 5 − 2 + 1 = 3 5-2+1=3 5−2+1=3。第四个人本来赢了三场,然后把我们打败了赢了4场,第五个人算上赢我们的那一场一共赢了5场。
但是我们观察一下能不能再上升一名呢,如果我们放弃第三个人,我们去打第四个人的话。那么我们还是赢了3场,但是此时第四个人的本来靠赢我们多了一场,但是现在被我们打败了,场数和我们一样了。所以我们的排名相应的会上升一名。
我们总结一下 ,就是假设我们赢了res场,这个是已经确定的,只需要看一看我们在a数组里的第res+1个人是否在我们的被打败的名单里即可。如果在的话我们就名次上升一。不在的话就正常。
AC代码
#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 10;
int a[N], b[N];
int pre[N];
void solve()
{
int n, m;
cin >> n >> m;
for (int i = 0; i < n; i++)
{
cin >> a[i];
b[i] = a[i];
}
sort(b, b + n);
pre[0] = b[0];
for (int i = 1; i < n; i++)
pre[i] = pre[i - 1] + b[i];
int res = upper_bound(pre, pre + n, m) - pre - 1;
if (res == -1)//相当于一局没赢,直接最后一名
{
cout << n + 1 << endl;
return ;
}
else if (res == n - 1)//相当于赢了至少和第n个人一样的场数,那么直接最后一名
{
cout << 1 << endl;
return ;
}
else
{
int t = m - pre[res];//看我们还剩下的时间
if (t + b[res] >= a[res + 1])//判断一下我们第res+1个数能不能被打败。
//为了让他可以被打败,我们在选好的数组里退回一个时间最大的
cout << n - res - 1 << endl;
else
cout << n - res << endl;
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T;
cin >> T;
while (T--)
{
solve();
}
return 0;
}