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