HNUCM 1372百舸争流 (贪心)

                                       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);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值