题意 :
- n个队伍参加两轮比赛,给第一轮结束后每个队伍的分数,以及第二轮第i名可以获得的分数。
- 求所有队伍的最高名次和最低名次(同分数名次并列)。
思路 :
- 最高排名(让它下面的人最多),将它本身加上最大的b分,总分记为sc,剩余的a中从小到大枚举,让它们尽可能拿走最大的b分且总分小于等于sc分,到b中分数已经被枚举到了最后一个的时候就break了,a中剩下的个数就是排名在这个对象上面的了。
- 最低排名(让它上面的人最多),将它本身加上最小的b分,总分记为sc,剩余的a中从大到小枚举,如果本身就比sc还大,说明加什么都会比sc大,直接让这个对象上面的人数 ++ 即可。
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <ctime>
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define lowbit(x) (x&-x)
using namespace std;
const double pi = acos(-1);
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<long, long> PLL;
const int N = 5e3 + 10;
ll a[N], b[N], r[N];
bool cmp1(int x, int y)
{
return a[x] > a[y];
}
bool cmp2(ll x, ll y)
{
return x > y;
}
int main()
{
IOS;
int _; cin >> _;
while (_ -- )
{
int n;
cin >> n;
for (int i = 1; i <= n; i ++ ) cin >> a[i];
for (int i = 1; i <= n; i ++ ) cin >> b[i];
for (int i = 1; i <= n; i ++ ) r[i] = i;
sort(r + 1, r + n + 1, cmp1); // r中元素是将a数组元素从高到低排序后在a中的序号,即r[1]是a数组中元素最大值的下标
sort(b + 1, b + n + 1, cmp2); // b中元素从大到小
for (int i = 1; i <= n; i ++ )
{
int hi = 0, lo = 0;
// 最高排名
ll sc = a[i] + b[1], k = 2; // 本身给予最高分
for (int j = n; j >= 1; j -- ) // a中得分从低到高枚举
{
ll jj = r[j]; // j == n时,jj是a数组中最小元素的下标
if (jj == i) continue;
while (a[jj] + b[k] > sc && k <= n) ++ k ; // 找使得总得分小于等于sc的b中分数
if (k <= n) ++ hi ; // 找得到就 ++ ,使hi尽可能多,即在最高排名下,使得总得分小于等于sc的尽可能多
++ k ;
if (k > n) break;
}
hi = n - hi; // 剩下的分都比它高
// 最低排名
sc = a[i] + b[n], k = n - 1;
for (int j = 1; j <= n; j ++ )
{
ll jj = r[j];
if (jj == i) continue;
if (a[jj] > sc)
{
++ lo ;
continue;
}
while (a[jj] + b[k] <= sc && k >= 1) -- k ; // 找使得总得分大于sc的
if (k < 1) break;
++ lo ;
-- k ;
}
cout << hi << " " << lo + 1 << endl;
}
}
return 0;
}