5 10
题意:n个人进行决斗,共有三场比赛,前两场比赛的成绩已经知道了,第三场的成绩未知,已知如果A前两场比赛每一场比赛成绩都严格高于B,那么A的第三场成绩一定大于等于B,最后的结果按三场总成绩从高到低排序,问每一个人最好的名次和最差的名词分别可能为多少。
思路:先考虑一个人A最好的情况,那么A得到的分数为650分,那么之前两场严格高于她的人最后一定也高于她,如果B之前一门小于等于她,另一门高于她,这种情况最后也不会比她高,因为可以另B的第三门成绩为0,那么A的成绩一定是大于等于B的(等于的情况有两种,一种是第二门成绩为0,但是B的第二门成绩为650,第一门成绩两者相同,另一种是第一种第二种反一下),又因为两者成绩相等自己不会退后名词,所以可以不用管。再考虑A最坏的情况,我们考虑比A考的差的人,这里和之前一样,只是要考虑(0,0,a[i]-1,b[i]-1)的总数,这里还要考虑和她成绩相同的情况,就是A的a[i]或者b[i]=650,要减去这些,然后用n减去比她考的差的人数就是答案了。
注意:这题不能用树状数组,因为会超时,又因为点的坐标大小都很小,所以可以用s[i][j]表示x小于等于i,y小于等于j的坐标总数。
#include<iostream> #include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<string> #include<bitset> #include<algorithm> using namespace std; typedef long long ll; typedef long double ldb; #define inf 99999999 #define pi acos(-1.0) #define NN 500050 #define MM 650 int a[NN],b[NN]; int k[MM+10][MM+10],s[MM+10][MM+10]; int solve(int p,int q,int P,int Q) { int i,j; if(P<0 || Q<0)return 0; int sum=s[P][Q]; if(p>0){ sum-=s[p-1][Q]; } if(q>0){ sum-=s[P][q-1]; } if(p>0 && q>0){ sum+=s[p-1][q-1]; } return sum; } int main() { int n,m,i,j,c,d; while(scanf("%d",&n)!=EOF) { memset(k,0,sizeof(k)); memset(s,0,sizeof(s)); for(i=1;i<=n;i++){ scanf("%d%d",&a[i],&b[i]); k[a[i] ][b[i] ]++; } for(i=0;i<=MM;i++){ for(j=0;j<=MM;j++){ s[i][j]=k[i][j]; if(i>0){ s[i][j]+=s[i-1][j]; } if(j>0){ s[i][j]+=s[i][j-1]; } if(i>0 && j>0){ s[i][j]-=s[i-1][j-1]; } } } for(i=1;i<=n;i++){ printf("%d ",solve(a[i]+1,b[i]+1,MM,MM)+1 ); printf("%d\n",n-solve(0,0,a[i]-1,b[i]-1)-k[a[i] ][0]*(b[i]==MM)-k[0][b[i] ]*(a[i]==MM) ); } } return 0; }