题目大意
有
n
n
n 个人,每个人有一个初始分值,然后再给你
n
n
n 个数,表示接下来一场比赛获得第
i
i
i 名的得分。问你这场比赛之后每个人可能获得的最好名次和最坏名次。
分数并列则名次并列,且并列名次跳过,如四个人得分为5 3 3 2,那么排名是1 2 2 4。
n
<
=
50001
<
=
T
<
=
20
n <= 5000 1 <= T <= 20
n<=50001<=T<=20,最多有8组数据
n
>
100
n > 100
n>100
解题思路
考虑直接暴力每个人的最好名次和最坏名次复杂度是
O
(
n
2
l
o
g
n
)
=
k
e
9
O(n^2logn) = ke9
O(n2logn)=ke9,杭电的评测机是跑不过了
我们先将初始分值
a
i
a_i
ai 和 下一场的得分
b
i
b_i
bi 从小到大排序。
考虑第
i
i
i 个人的最佳名次
设初始最佳名次为1,得分为
n
o
w
=
a
i
+
b
n
now = a_i + b_n
now=ai+bn,显然想获得最佳名次肯定是拿最高的分,我们可以想,第1到
i
−
1
i-1
i−1个人的得分一定不会超过第
i
i
i 个人,(因为他们初始分比第
i
i
i 个人少,得分又比第
i
i
i 个人少,所以名次一定更差),所以我们只需要考虑
i
+
1
i+1
i+1 到
n
n
n。
设第
j
j
j 个人的获得的所拿的分为
b
k
b_k
bk,如果
a
j
+
b
k
>
n
o
w
a_j + b_k > now
aj+bk>now,那么我们让第
j
j
j 个人拿 第
b
k
−
1
b_{k-1}
bk−1,直到
a
j
+
b
k
<
=
n
o
w
a_j + b_k <= now
aj+bk<=now,这样才不会影响第
i
i
i 个人的排名。如果
k
=
0
k = 0
k=0,说明从第
j
j
j 个人开始,他们的得分一定比
i
i
i 高,我们直接让
i
i
i 的排名加上
n
−
j
+
1
n-j+1
n−j+1即可。
为什么可以这样呢?因为如果第
j
j
j 个人不拿
b
k
b_k
bk(说明
a
j
+
b
k
>
n
o
w
a_j + b_k > now
aj+bk>now),那么第
j
+
1
j+1
j+1 个人也一定不会拿
b
k
b_k
bk,因为
a
j
+
1
+
b
k
>
a
j
+
b
k
>
n
o
w
a_{j+1} + b_k > a_j + b_k > now
aj+1+bk>aj+bk>now,同样会超过第
i
i
i 个人的得分。这样我们就可以去掉一个
l
o
g
n
logn
logn的复杂度。
考虑第
i
i
i 个人的最坏名次也是同理,不过我们,要注意一下,如果初始化最坏名次为
n
n
n ,那么如果有多个人初始得分相同,我们一定要从最后一个开始跑,(因为相同分数,排名是记在前面的),而且初始得分相同,那么最坏排
名也一定相同,所以我们跑一个就可以了
最终复杂度
O
(
n
2
)
O(n^2)
O(n2)
Code
#include <bits/stdc++.h>
#define ll long long
#define qc ios::sync_with_stdio(false); cin.tie(0);cout.tie(0)
#define fi first
#define se second
#define PII pair<int, int>
#define PLL pair<ll, ll>
#define pb push_back
using namespace std;
const int MAXN = 5007;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1e9 + 7;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
int n;
struct node{
ll x, idx;
bool operator<(node b) const{
return x < b.x;
}
}a[MAXN];
ll b[MAXN];
void solve(){
cin >> n;
for (int i = 1; i <= n; ++i){
cin >> a[i].x;
a[i].idx = i;
}
for (int i = 1; i <= n; ++i){
cin >> b[i];
}
sort(a+1,a+1+n);
sort(b+1, b+1+n);
vector<PII> ans(n+1);
a[n+1].x = -1;
int ls = 1;
for (int i = 1; i <= n; ++i){
int l = 1, r = n;
ll now = a[i].x + b[r--];
int pm = 1;
for (int j = i+1; j <= n; ++j){
while(l <= r && a[j].x + b[r] > now) {
r--;
}
if(l > r){
pm += (n - j + 1);
break;
}
r--;
}
ans[a[i].idx].fi = pm;
if(a[i].x == a[i+1].x)
continue;
pm = n;
l = 1, r = n;
now = a[i].x + b[l++];
for (int j = i-1; j >= 1; --j){
while(l <= r && a[j].x + b[l] <= now) {
l++;
}
if(l > r){
pm -= j;
break;
}
l++;
}
for (int j = ls; j <= i; ++j){
ans[a[j].idx].se = pm;
}
ls = i+1;
}
for (int i = 1; i <= n; ++i){
cout << ans[i].fi << " " << ans[i].se << endl;
}
}
int main()
{
#ifdef ONLINE_JUDGE
#else
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
qc;
int T;
cin >> T;
// T = 1;
while(T--){
solve();
}
return 0;
}