日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

1095 解码PAT准考证 (25分)击破测试点3、4,50ms内通关

發布時間:2024/1/18 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 1095 解码PAT准考证 (25分)击破测试点3、4,50ms内通关 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1095 解碼PAT準考證 (25分)測試點34用時低于35ms

  • 前言
  • 一、題目簡介
  • 二、原題內容
    • 1. 設定
    • 2. 輸入格式
    • 3. 輸出格式
  • 三、題目分析
    • 1. 要求1分析
    • 2. 要求2分析
    • 3. 要求3分析
    • 4. 完整代碼
  • 總結


前言

肝了四五天,肝完了PAT乙級真題。1095 解碼PAT準考證 (25分)作為PAT乙級的最后一道題,題目的復雜程度相較前面的題目有所提升,對時間的把控要求也更高,基本上代表了乙級真題里的最高難度,屬于畢業題。如果采用復雜冗長的代碼和非緩存式的計算結構,很有可能使得此題的最后兩個測試點因為超時而無法通過。附上本文代碼,平均用時,測試點3、4用時30-50ms以內,測試點0、1用時5ms上下,測試點2用時14ms上下。


提示:以下是本篇文章正文內容,下面案例可供參考

一、題目簡介

給定準考證號及考試成績。
要求1:根據級別,輸出準考證號分數。(輸出多行)
要求2:根據考場號,輸出人數總分.(輸出單行)
要求3:根據日期,輸出考場號總人數.(輸出多行)

二、原題內容

1. 設定

PAT 準考證號由 4 部分組成:

  • 第 1 位是級別,即 T 代表頂級;A 代表甲級;B 代表乙級;
  • 第 2~4 位是考場編號,范圍從 101 到 999;
  • 第 5~10位是考試日期,格式為年、月、日順次各占 2 位;
  • 最后 11~13 位是考生編號,范圍從 000 到 999。

現給定一系列考生的準考證號和他們的成績,請你按照要求輸出各種統計信息。

2. 輸入格式

輸入首先在一行中給出兩個正整數 N(≤10000?? )和 M(≤100),分別為考生人數和統計要求的個數。

接下來 N 行,每行給出一個考生的準考證號和其分數(在區間 [0,100] 內的整數),其間以空格分隔。

考生信息之后,再給出 M 行,每行給出一個統計要求,格式為:類型 指令,其中

  • 類型 為 1 表示要求按分數非升序輸出某個指定級別的考生的成績,對應的 指令 則給出代表指定級別的字母;
  • 類型 為 2 表示要求將某指定考場的考生人數和總分統計輸出,對應的 指令 則給出指定考場的編號;
  • 類型 為 3 表示要求將某指定日期的考生人數分考場統計輸出,對應的 指令 則給出指定日期,格式與準考證上日期相同。

3. 輸出格式

對每項統計要求,首先在一行中輸出 Case #: 要求,其中 # 是該項要求的編號,從 1 開始;要求 即復制輸入給出的要求。隨后輸出相應的統計結果:

  • 類型 為 1 的指令,輸出格式與輸入的考生信息格式相同,即 準考證號 成績。對于分數并列的考生,按其準考證號的字典序遞增輸出(題目保證無重復準考證號);
  • 類型 為 2 的指令,按 人數 總分 的格式輸出;
  • 類型 為 3 的指令,輸出按人數非遞增順序,格式為 考場編號 總人數。若人數并列則按考場編號遞增順序輸出。
    如果查詢結果為空,則輸出 NA。

輸入樣例:

8 4 B123180908127 99 B102180908003 86 A112180318002 98 T107150310127 62 A107180908108 100 T123180908010 78 B112160918035 88 A107180908021 98 1 A 2 107 3 180908 2 999

輸出樣例:

Case 1: 1 A A107180908108 100 A107180908021 98 A112180318002 98 Case 2: 2 107 3 260 Case 3: 3 180908 107 2 123 2 102 1 Case 4: 2 999 NA

三、題目分析

1. 要求1分析

類型 為 1 表示要求按分數非升序輸出某個指定級別的考生的成績,對應的 指令 則給出代表指定級別的字母;

即:給定級別(ID[0]),輸出排序后的編號(ID)和得分(score)
定義。給定結構體:

struct Info {string id; //名字int score; //得分 };

定義。給定排序方法:

int cmp(Info a, Info b) {return a.score == b.score ? a.id < b.id : a.score > b.score; }

處理輸入。
使用數組存儲各個級別對應的個人信息結構體。‘A’, ‘B’, 'T’各自對應一組結構體集合。由于map的特性,如果沒有對應的級別,也不會額外創建這組結構體。
特別說明的是,只有case1需要提前全部計算完畢三種組合,以便于查詢過程中隨用隨取。其余Case2,Case3,輸入對應的所有組合數量多,如果提前全部計算,查詢數目遠遠小于計算的數目,會導致大量不必要的開銷。

vector<Info> vInfo;map<char, vector<Info> >mci;for (int i = 0; i < N; i++) {Info info;cin >> info.id;scanf("%d", &info.score);vInfo.push_back(info);mci[info.id[0]].push_back(info);}for (map<char, vector<Info> >::iterator it = mci.begin(); it != mci.end(); it++) {sort(mci[it->first].begin(), mci[it->first].end(), cmp);}

處理輸出。map類型的mci.count(char)==1意義是判斷該關鍵字是否在字典中出現過,相當于mci.find(char)!=mci.end()。

case 1: {scanf("%c", &c);printf("Case %d: %d %c\n", i + 1, choice, c);if (mci.count(c)==1) {for (int i = 0; i < mci[c].size(); i++) {cout << mci[c][i].id;printf(" %d\n", mci[c][i].score);}}else {printf("NA\n");}break;}

2. 要求2分析

  • 類型 為 2 表示要求將某指定考場的考生人數和總分統計輸出,對應的 指令 則給出指定考場的編號;

即:給定考場號(ID[1-3]),輸出該考場號對應的總人數(num)和總得分(score)。
定義。給定結構體:

struct case2 {int num, score; }; // 定義map2,將考場號(string)類型,轉化為case2類型。用于緩存處理。 map<string, case2> mp2;

如果沒有緩存處理,代碼是如下結構:

case 2: {cin >> placeId;printf("Case %d: %d ", i + 1, choice);cout << placeId << endl;score = num = 0;for(int i = 0; i < N; i++){if (vInfo[i].id.substr(1, 3) == placeId) {num++;score += vInfo[i].score;}}if (num > 0) {printf("%d %d\n", num, score);}else printf("NA\n");break;}

這一串代碼很簡潔,把要處理的任務都處理掉了。每次查詢都會遍歷一遍所有考生的信息,檢查N個考生的考場號是否與待查詢的考場號相符。
但是這樣做問題很明顯:如果接下來100條查詢都和第一次的查詢一樣,都在查詢某一個場次,則會訪問100*N次,時間復雜度為O(MN)。而如果將第一次查詢的結果保存在一個字典中,下一次查詢時候就可以直接讀出,訪問次數為N+100次,時間復雜度降為O(M+N)。
每次查詢時,首先看該記錄是否已經被緩存,如果已經被緩存,則訪問并退出;否則,逐個檢查N個考生的考場號,并將結果進行緩存。緩存后的代碼如下。

case 2: {cin >> placeId;printf("Case %d: %d ", i + 1, choice);cout << placeId << endl;if (mp2.count(placeId)) {printf("%d %d\n", mp2[placeId].num, mp2[placeId].score);break;}score = num = 0;for(int i = 0; i < N; i++){if (vInfo[i].id.substr(1, 3) == placeId) {num++;score += vInfo[i].score;}}if (num > 0) {printf("%d %d\n", num, score);case2 cs;cs.num = num;cs.score = score;mp2[placeId] = cs;}else printf("NA\n");break;}

3. 要求3分析

類型 為 3 表示要求將某指定日期的考生人數分考場統計輸出,對應的 指令 則給出指定日期,格式與準考證上日期相同。

即:給定日期(ID[4-9]),輸出排序后的考場號(ID[1-3])和總人數(num)
復用前文的結構體,因為要求3的輸出內容也是一個string和int:

struct Info {string id; //考場號int score; //總人數 }; //用于緩存的字典。 map<string, vector<Info> > mp3;

如果沒有緩存處理,代碼是如下結構:

case 3: {cin >> date;printf("Case %d: %d ", i + 1, choice);cout << date << endl;//mp用于存放給定日期下,考場編號到該考場考生人數的映射。map<string, int> mp;//逐個比對日期信息for (int i = 0; i < N; i++) {//日期信息相符if (vInfo[i].id.substr(4, 6) == date) {placeId = vInfo[i].id.substr(1, 3);//計算當日每個考場內的學生總數。if (mp.count(placeId)) {mp[placeId]++;}else {mp[placeId] = 1;}}}//當日沒有分配考場if (mp.size() == 0) {printf("NA\n");break;}//只有形成了結構體的向量(數組),才能方便進行排序vector<Info> dp;Info temp;for (map<string, int>::iterator it = mp.begin(); it != mp.end(); it++) {//ID:考場編號。score:該考場內的考生temp.id = it->first;temp.score = it->second;dp.push_back(temp);}//排序sort(dp.begin(), dp.end(), cmp);for (int i = 0; i < dp.size(); i++) {cout << dp[i].id;printf(" %d\n", dp[i].score);}break;}

同理,是否采用緩存結構,也是數量級O(MN)到數量級O(M+N)的轉換。已經在必要的步驟處做了注釋。與上段代碼增加的地方就是緩沖的內容。

case 3: {cin >> date;printf("Case %d: %d ", i + 1, choice);cout << date << endl;if (mp3.count(date)) {if (mp3[date].size() == 0) {printf("NA\n");break;}for (int i = 0; i < mp3[date].size(); i++) {cout << mp3[date][i].id;printf(" %d\n", mp3[date][i].score);}break;}//mp用于存放給定日期下,考場編號到該考場考生人數的映射。map<string, int> mp;//逐個比對日期信息for (int i = 0; i < N; i++) {//日期信息相符if (vInfo[i].id.substr(4, 6) == date) {placeId = vInfo[i].id.substr(1, 3);//計算當日每個考場內的學生總數。if (mp.count(placeId)) {mp[placeId]++;}else {mp[placeId] = 1;}}}//當日沒有分配考場if (mp.size() == 0) {printf("NA\n");vector<Info> dp;mp3[date] = dp;break;}//只有形成了結構體的向量(數組),才能方便進行排序vector<Info> dp;Info temp;for (map<string, int>::iterator it = mp.begin(); it != mp.end(); it++) {//ID:考場編號。score:該考場內的考生總數。temp.id = it->first;temp.score = it->second;dp.push_back(temp);}//排序sort(dp.begin(), dp.end(), cmp);for (int i = 0; i < dp.size(); i++) {cout << dp[i].id;printf(" %d\n", dp[i].score);}mp3[date] = dp;break;}

4. 完整代碼

// 創作By:zhangwenniu@163.com,轉載請注明出處。#include <string> #include <iostream> #include <vector> #include <map> #include <algorithm> using namespace std; const int maxn = 10010; struct Info {string id;int score; }; int cmp(Info a, Info b) {return a.score == b.score ? a.id < b.id : a.score > b.score; } struct case2 {int num, score; }; int main() {int N, M, score, num;string id;scanf("%d%d", &N, &M);vector<Info> vInfo;map<char, vector<Info> >mci;for (int i = 0; i < N; i++) {Info info;cin >> info.id;scanf("%d", &info.score);vInfo.push_back(info);mci[info.id[0]].push_back(info);}for (map<char, vector<Info> >::iterator it = mci.begin(); it != mci.end(); it++) {sort(mci[it->first].begin(), mci[it->first].end(), cmp);}int choice;char c, space;string placeId;string date;string others;map<string, case2> mp2;map<string, vector<Info> > mp3;for (int i = 0; i < M; i++) {scanf("%d%c", &choice, &space);switch (choice) {case 1: {scanf("%c", &c);printf("Case %d: %d %c\n", i + 1, choice, c);if (mci.count(c)==1) {for (int i = 0; i < mci[c].size(); i++) {cout << mci[c][i].id;printf(" %d\n", mci[c][i].score);}}else {printf("NA\n");}break;}case 2: {cin >> placeId;printf("Case %d: %d ", i + 1, choice);cout << placeId << endl;if (mp2.count(placeId)) {printf("%d %d\n", mp2[placeId].num, mp2[placeId].score);break;}score = num = 0;for(int i = 0; i < N; i++){if (vInfo[i].id.substr(1, 3) == placeId) {num++;score += vInfo[i].score;}}if (num > 0) {printf("%d %d\n", num, score);case2 cs;cs.num = num;cs.score = score;mp2[placeId] = cs;}else printf("NA\n");break;}case 3: {cin >> date;printf("Case %d: %d ", i + 1, choice);cout << date << endl;if (mp3.count(date)) {if (mp3[date].size() == 0) {printf("NA\n");break;}for (int i = 0; i < mp3[date].size(); i++) {cout << mp3[date][i].id;printf(" %d\n", mp3[date][i].score);}break;}//mp用于存放給定日期下,考場編號到該考場考生人數的映射。map<string, int> mp;//逐個比對日期信息for (int i = 0; i < N; i++) {//日期信息相符if (vInfo[i].id.substr(4, 6) == date) {placeId = vInfo[i].id.substr(1, 3);//計算當日每個考場內的學生總數。if (mp.count(placeId)) {mp[placeId]++;}else {mp[placeId] = 1;}}}//當日沒有分配考場if (mp.size() == 0) {printf("NA\n");vector<Info> dp;mp3[date] = dp;break;}//只有形成了結構體的向量(數組),才能方便進行排序vector<Info> dp;Info temp;for (map<string, int>::iterator it = mp.begin(); it != mp.end(); it++) {//ID:考場編號。score:該考場內的考生總數。temp.id = it->first;temp.score = it->second;dp.push_back(temp);}//排序sort(dp.begin(), dp.end(), cmp);for (int i = 0; i < dp.size(); i++) {cout << dp[i].id;printf(" %d\n", dp[i].score);}mp3[date] = dp;break;}default: {getline(cin, others);printf("Case %d: %d ", i + 1, choice);cout << others << endl;printf("NA\n");}}} }

總結

提示:注意第三問,要求在給定日期下的某考場,相當于是日期+考場(ID[1-9])作為總關鍵字進行統計。當心陷阱。以上就是今天要講的內容,本文僅僅簡單介紹了緩沖思想的應用。最后放上AC的截圖,僅供大家參考。

總結

以上是生活随笔為你收集整理的1095 解码PAT准考证 (25分)击破测试点3、4,50ms内通关的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。