1. 程式人生 > >1372: 百舸爭流解題報告---貪心 & 名次問題

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