1372: 百舸争流
时间限制: 1 内存限制: 128 MB
题目描述
橘子洲风景区位于湖南省长沙市市区对面的湘江江心,是湘江中最大的名洲,由南至北,横贯江心,西望
岳麓山,东临长沙城,四面环水,绵延数十里,狭处横约 40 米,宽处横约 140 米,形状是一个长岛,是
国家重点风景名胜区。
一天,N 名选手参加了一年一度的橘洲竞渡大赛,现在只剩下最后一场决赛了!
赛制为积分制,N 名选手的积分分别为 A1 到 AN。决赛的积分规则如下:第一名得 B1 分,第二名得 B2
分,……,第 m 名得 Bm 分,第 m+1 名至第 n 名不得分。最后第 i 名选手的总得分为 Ai 加上他在决
赛中的得分。
我们按总分为第一关键字、名字的字典序为第二关键字对选手进行排序。现告诉你一名选手的名字,希望
你告诉他,他最终的排名最前可能是多少,最后可能是多少。
输入
单组数据。
第一行为一个数 n,表示有 n 名选手 (1 ≤ n ≤ 105)。
接下来有 n 行,每行由一个字符串 S 和一个非负整数 Ai 表示,代表该人的名字和决赛之前的总分。
(名字仅由英文字母和数字表示,长度不超过 20,没有相同名字的两个人,0 ≤ Ai ≤ 106)。
接下来一个数 m(0 ≤ m ≤ n)。
接下来一行 m 个数字依次表示 B1, B2, B3, · · · , Bm (0 ≤ Bi ≤ 106)。
最后一个字符串表示询问的选手的名字。
输出
输出两个数,第一个表示最终排名最前可能多少,第二个表示最后可能多少。
样例输入
3
CH1 10
CH2 20
CH3 40
2
20 10
CH1
贪心,难点在于获得最好/最坏成绩的策略。
所有选手排序(成绩优先,字典序其次),某位选手的最好成绩就是从成绩最坏的选手开始,只要存在
(选手现成绩 + 决赛成绩<所求选手成绩 )|| (成绩相等 && 字典序小些),选手排名就上升。
最坏成绩同理。
怎么去遍历选手,就是要选取好贪心策略。
AC Code:
#include <cstdio>
#include <cmath>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<map>
#include<queue>
#include<climits>
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
using namespace std;
typedef long long ll;
static const int MAX_N = 1e5 + 5;
struct Node{
public :
char name[25];
int score;
}vv[MAX_N];
bool cmp(Node a, Node b){
if(a.score != b.score) return a.score > b.score;
return strcmp(a.name, b.name) < 0;
//strcmp比较的是字符串大小(a.name比b.name小则返回<0的值),字符串小的字典序大
}
int val[MAX_N];
int main(){
int n;
scanf("%d", &n);
for(int i = 0; i < n; i++){
scanf("%s%d", vv[i].name, &vv[i].score);
}
int m;
scanf("%d", &m);
for(int i = 0; i < m; i++){
scanf("%d", &val[i]);
}
char str[25];
scanf("%s", str);
sort(val, val + n); //这里从n开始完全OK,m < n则后面n - m个选手成绩只能+0
sort(vv, vv + n, cmp);
int vgra;
for(int i = 0; i < n; i++){
if(!strcmp(str, vv[i].name)){
vgra = vv[i].score;
}
}
int vgra1 = vgra + val[n - 1];
int cur1 = n; //成绩小的选手从大成绩开始选 ---->最好成绩
for(int i = n - 1, j = n - 2; i >= 0 && j >= 0; i--){
if(!strcmp(str, vv[i].name)) continue;
while(j >= 0){
if(vv[i].score + val[j] < vgra1 || (vv[i].score + val[j] == vgra1 && strcmp(vv[i].name, str) > 0)){
break;
}
j--;
}
if(j < 0) break;
j--;
cur1--;
}
int vgra2 = vgra + val[0];
int cur2 = 1;
for(int i = 0, j = 1; i < n && j < n; i++){
//成绩大的选手从小成绩开始选 ----->最坏成绩
if(!strcmp(str, vv[i].name)) continue;
while(j < n){
if(vv[i].score + val[j] > vgra2 || (vv[i].score == vgra2 && strcmp(vv[i].name, str) < 0)){
break;
}
j++;
}
if(j >= n) break;
j++;
cur2++;
}
printf("%d %d\n", cur1, cur2);
}