Description:
在三场考试中,有
n
n
n为选手,现在已知每位选手的第一场和第二场的分数,并且知道若选手
A
A
A的第一场和第二场的分数都严格大于选手
B
B
B,则
A
A
A的第三场的分数一定大于
B
B
B,以及每场的分数为0~650。求每位选手最后总分的最高排名和最低排名。
n
≤
500000
n\le50 0000
n≤500000
Solution:
- 模拟小数据,发现,满足题意的严格大于的选手 A A A的排名一定比 B B B高,小于同理,即 A A A的最高排名-1, B B B的最低排名+1。
- 由于分数比较小,那么我们可以直接用二维前缀和来维护。
- 但是第三场的分数最高为650。考虑 A A A最高排名,如果给了 A A A 650分,给大于 A A A的人650分,给其他人0分,可能有其他人总分大于等于 A A A的。
- 其实不会大于,只会等于,因为既然那个人不大于 A A A,最多可能是有一场等于 A A A,有一场为650。
- 而 A A A那一场最低为0,也就是两人之前的分差最多为650。那么加上第三场后两人恰好相等。同理,考虑最低排名,给$A$0分,给其他人650分,也会有人和A相等。
- 由于分数相同取高位,最高排名不用管,只需要在最低排名判断,如果 A A A有一场为650,那么排名就要减去另一场相等,这一场为0的人数。
Code:
#include<bits/stdc++.h>
using namespace std;
#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t) for(int i=(f),i##_end_=(t);i<i##_end_;++i)
#define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;--i)
#define ll long long
template<class T>inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
template<class T>inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
template<class T>inline void Rd(T &x){
x=0;char c;int f=1;
while((c=getchar())<48)if(c=='-')f=-1;
do x=(x<<1)+(x<<3)+(c^48);
while((c=getchar())>47);
x*=f;
}
const int N=5e5+2,M=655;
int n;
int A[N],B[N];
int sum1[M][M],sum2[M][M];
int main(){
// freopen("coci.in","r",stdin);
// freopen("coci.out","w",stdout);
Rd(n);
REP(i,1,n) {
Rd(A[i]),Rd(B[i]);
sum1[A[i]][B[i]]++;
sum2[A[i]][B[i]]++;
}
REP(i,0,M-5) REP(j,0,M-5){
if(i>0) sum1[i][j]+=sum1[i-1][j];
if(j>0) sum1[i][j]+=sum1[i][j-1];
if(i>0 && j>0) sum1[i][j]-=sum1[i-1][j-1];
}
REP(i,1,n){
int Mx=1+n-sum1[650][B[i]]-sum1[A[i]][650]+sum1[A[i]][B[i]];
int Mn=n-((!A[i] || !B[i])?0:sum1[A[i]-1][B[i]-1]);
if(A[i]==650) Mn-=sum2[0][B[i]];
if(B[i]==650) Mn-=sum2[A[i]][0];
printf("%d %d\n",Mx,Mn);
}
return 0;
}