题目大意:有\(n\)个人,给定他们的第一轮成绩和第二轮成绩,如果\(A\)第一轮成绩和第二轮成绩均大于\(B\)的,那么\(A\)的第三轮成绩大于等于\(B\)的第三轮成绩。求每个人可能的最小、最大排名
思维
分析:
首先最小排名等于成绩一定比他高的人数\(+1\),这个比较显然。最大排名等于\(n\)减去成绩一定不高于他的人数
先看最小排名,成绩一定比他高,满足以下两个条件之一(设当前这个人为\(now\),另一个人为\(A\),两次成绩为\(X,Y\))
\(1.\begin{cases}X_{now}<X_A \\ Y_{now}<Y_A\end{cases}\)
\(2.X_{now}+Y_{now}+650<X_A+Y_A\)(哪怕你第三次阿克总分都没有另一个人第三次抱零高)被巨佬碾压
满足第二个的条件的一定包含在第一个条件里面了,当第二个条件成立时,不妨假设\(X_{now} \geq X_{A}\)
那么有\(X_A-X_{now} \leq0\)
由第二个条件推出\(Y_{now}+650-Y_{A}<X_A-X_{now}\)
由于\(X,Y\in[0,650]\),不等号左边是个非负数,右边是个非正数,显然不成立。得证。
所以求最小排名只需要一个前缀和。
最大排名,成绩一定不高于他,满足以下两个条件之一
\(1.\begin{cases}X_{now}>X_A \\ Y_{now}>Y_A\end{cases}\)
\(2.X_{now}+Y_{now}\geq X_A+Y_A+650\)(哪怕你第三次抱零总分都不低于另一个人第三次阿克)巨佬碾压别人
容斥原理可以算,我们证明满足第二个条件,但是不在第一个条件里面的最多只有两个点。
仍假设第二个条件成立,假设\(X_{now}\leq X_A\),那么有
\(X_{now}-X_{A}\geq Y_A+650-Y_{now}\)
\(X_{now}-X_A\leq0\)
左边是个非正数,右边是个非负数,成立时两侧都为\(0\)
有\(\begin{cases}Y_{now}=650\\X_A=X_{now}\\Y_A=0\end{cases}\)
另一种情况同理,仍然前缀和来做
#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
const int maxn = 5e5 + 100,maxk = 650;
inline int read(){
int x = 0;char c = getchar();
while(!isdigit(c))c = getchar();
while(isdigit(c))x = x * 10 + c - '0',c = getchar();
return x;
}
struct node{int x,y;}val[maxn];
int n,tmp[maxk + 10][maxk + 10],pre[maxk + 10][maxk + 10],suf[maxk + 10][maxk + 10];
inline int query_pre(int x,int y){
if(x < 0 || y < 0)return 0;
return pre[x][y];
}
int main(){
n = read();
for(int i = 1;i <= n;i++)
val[i].x = read(),val[i].y = read();
for(int i = 1;i <= n;i++)
tmp[val[i].x][val[i].y]++;
pre[0][0] = tmp[0][0];
for(int i = 1;i <= 650;i++)
pre[0][i] = pre[0][i - 1] + tmp[0][i];
for(int i = 1;i <= 650;i++)
pre[i][0] = pre[i - 1][0] + tmp[i][0];
for(int i = 1;i <= 650;i++)
for(int j = 1;j <= 650;j++)
pre[i][j] = pre[i - 1][j] + pre[i][j - 1] - pre[i - 1][j - 1] + tmp[i][j];
suf[650][650] = tmp[650][650];
for(int i = 649;i >= 0;i--)
suf[650][i] = suf[650][i + 1] + tmp[650][i];
for(int i = 649;i >= 0;i--)
suf[i][650] = suf[i + 1][650] + tmp[i][650];
for(int i = 649;i >= 0;i--)
for(int j = 649;j >= 0;j--)
suf[i][j] = suf[i + 1][j] + suf[i][j + 1] - suf[i + 1][j + 1] + tmp[i][j];
for(int i = 1;i <= n;i++){
int x = val[i].x,y = val[i].y;
int ans2 = query_pre(x - 1,y - 1) + (x == 650) * tmp[0][y] + (y == 650) * tmp[x][0];
printf("%d %d\n",1 + suf[x + 1][y + 1],n - ans2);
}
return 0;
}