题意:有n个人在我未介入之前第i个人赢i-1场。第i个人有一个值b[i]。我有可以分配的一个数m如果我想赢第i个人我就要支出b[i]。即m-=b[i]。赢了一个人我的胜场加一,输了那个人的胜场加一。我需要和每个人都比一场。最终名次按照胜场从大到小为1.2.3......问如何分配我的m可以让我的名次尽量靠前。
思路:尽量让胜场更多,再想办法打败胜场跟我们相同的那个人,这样的话这个人的胜场不会加1。先对数组b进行从小到大的排序。我们应该尽量先打败权值较小的一直打到打不过为止。这时我们的胜场为x。如果我们没有全胜,一定能找到另外一个胜场为x的人。假如我们剩余的m加上排完序之后最后一个打败的人的权值>=这个胜场为x的人的权值则胜场不变。否则减一。(这里要加上最后一个打败的是因为我们要放弃选择为他分配时间,对结果不影响)在对胜场进行从大到小排序。找到和我们胜场相同的人的位置。这个人的名次就是我们的名次。如果胜场为n则提前返回1,胜场为-1则返回n+1。
代码:
#include <bits/stdc++.h>
using namespace std;
int n,m;
int a[1000006];
struct Edge{
int a,b;
}edge[1000006];
bool cmp1(Edge a,Edge b){
return a.b > b.b;
}
bool cmp(Edge a,Edge b){
return a.a < b.a;
}
void solve()
{
cin >> n >> m;
for(int i = 1;i <= n;i ++){
scanf("%d",&edge[i].a);
edge[i].b = i-1;
a[i-1] = edge[i].a;
}
sort(edge + 1,edge + 1 + n,cmp);
int win = 0;edge[0].a = 0;
for(int i = 1;i <= n;i ++){
if(m >= edge[i].a){
m -= edge[i].a ;
win ++;
}else{
if(m + edge[i - 1].a >= a[win]){
}else{
win --;
}break;
}
}
if(win >= n){
cout<<"1"<<endl;return;
}
if(win == -1){
cout << n + 1 << endl;return;
}
sort(edge + 1,edge + 1 + n,cmp1);
for(int i = 1;i <= n;i ++){
if(edge[i].b <= win){
cout << i << endl;
return;
}
}
}
int main()
{
int _ = 1;
cin >> _;
while(_ --)
{
solve();
}
return 0;
}