题目链接

题目大意:有\(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;
}

相关文章: