这题是一个需要处理字符串的模拟题。
下面是我最开始写出来的代码。
#include <cstdio>
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
using namespace std;
struct stu{
string id;
int score;
string site;
string date;
};
bool cmp(stu a,stu b){
if(a.score!=b.score)return a.score>b.score;
return a.id<b.id;
}
bool cmp2(pair<int,int> a,pair<int,int> b){
if(a.second!=b.second)return a.second>b.second;
return a.first<b.first;
}
void exec(){
int N,M;
cin>>N>>M;
vector<stu> stus(N);
vector<stu> t_stu,a_stu,b_stu;
for(int i=0;i<N;i++){
cin>>stus[i].id>>stus[i].score;
stus[i].site=stus[i].id.substr(1,3);
stus[i].date=stus[i].id.substr(4,6);
if(stus[i].id[0]=='T'){
t_stu.push_back(stus[i]);
}else if(stus[i].id[0]=='A'){
a_stu.push_back(stus[i]);
}else if(stus[i].id[0]=='B'){
b_stu.push_back(stus[i]);
}
}
sort(t_stu.begin(),t_stu.end(),cmp);
sort(a_stu.begin(),a_stu.end(),cmp);
sort(b_stu.begin(),b_stu.end(),cmp);
for(int i=0;i<M;i++){
int type;
string term;
cin>>type>>term;
cout<<"Case "<<i+1<<": "<<type<<" "<<term<<endl;
if(type==1){
if(term=="T"){
if(t_stu.size()==0){cout<<"NA"<<endl;continue;}
for(auto stu:t_stu){
cout<<stu.id<<" "<<stu.score<<endl;
}
}else if(term=="A"){
if(a_stu.size()==0){cout<<"NA"<<endl;continue;}
for(auto stu:a_stu){
cout<<stu.id<<" "<<stu.score<<endl;
}
}else if(term=="B"){
if(b_stu.size()==0){cout<<"NA"<<endl;continue;}
for(auto stu:b_stu){
cout<<stu.id<<" "<<stu.score<<endl;
}
}
}else if(type==2){
int cnt=0,total_score=0;
for(auto st:stus){
if(st.site==term){
cnt++;
total_score+=st.score;
}
}
if(cnt==0){cout<<"NA"<<endl;continue;}
cout<<cnt<<" "<<total_score<<endl;
}else if(type==3){
vector<int> res;
for(auto st:stus){
if(st.date==term){
res.push_back(stoi(st.site));
}
}
int cnt[1000]={0};
for(int i=0;i<res.size();i++)cnt[res[i]]++;
vector<pair<int,int> > vp;
for(int i=0;i<1000;i++){
if(cnt[i]!=0){
vp.push_back(make_pair(i,cnt[i]));
}
}
sort(vp.begin(),vp.end(),cmp2);
if(vp.size()==0){
cout<<"NA"<<endl;
continue;
}
for(int i=0;i<vp.size();i++){
cout<<vp[i].first<<" "<<vp[i].second<<endl;
}
}
}
}
int main(){
freopen("data.in","r",stdin);
exec();
return 0;
}
我卡在了 type3 的情况。
因为我不知道应该怎样统计个数。
后来想了个办法,开一个1000的数组,然后初始化为0,再遍历site,给site对应的数组元素加1。
接着把site和对应的计数的值放入vector<pair<int,int> >里进行排序。
这种做法拿了19分。在测试点3、4超时了。
所以我不知道超时在什么地方,难道是用了cin这种东西?
或者是,应该对数据进行预处理,而不是每来一个请求计算一次?
不对,在计算某天的考点数据时,必须要先获得日期才有意义,不然会做大量可能无用的计算(比如把出现过的所有日期都算一遍)。
想不到办法,就去看了柳神的代码。
发现他用了两个加速技巧:
- unordered_map
- cmp 函数引用来传参数
unordered_map 我不会用,所以下面这段代码需要记下来。
unordered_map<string, int> m;
for (int j = 0; j < n; j++)
if (v[j].t.substr(4, 6) == s)
m[v[j].t.substr(1, 3)]++;
for (auto it : m) ans.push_back({it.first, it.second});
unordered_map 的 int 默认为1,所以可以直接 ++。
并且遍历 unordered_map 时,用 it.first、it.second 来获得里面的键和值。
但是,我改完了 unordered_map 还是超时,不知道为啥。吃饭去了。
……
吃完饭回来,我是真佛了,一语成谶。
原来 3、4 测试点超时,真是因为输出的时候用了 cout,没用 printf。
下面就是我最后的代码。
#include <cstdio>
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <unordered_map>
using namespace std;
struct node{
string id;
int score;
string site;
string date;
};
bool cmp(const node& a,const node& b){
if(a.score!=b.score)return a.score>b.score;
return a.id<b.id;
}
void exec(){
int N,M;
cin>>N>>M;
vector<node> stu(N);
vector<node> tstu,astu,bstu;
for(int i=0;i<N;i++){
cin>>stu[i].id>>stu[i].score;
//把site和date直接计算保存,方便type2和type3的判断
stu[i].site=stu[i].id.substr(1,3);
stu[i].date=stu[i].id.substr(4,6);
//提前把三类考生分开放,可以方便的解决 type1 的问题
if(stu[i].id[0]=='T'){
tstu.push_back(stu[i]);
}else if(stu[i].id[0]=='A'){
astu.push_back(stu[i]);
}else if(stu[i].id[0]=='B'){
bstu.push_back(stu[i]);
}
}
for(int i=1;i<=M;i++){
int type;
string term;
cin>>type>>term;
printf("Case %d: %d %s\n",i,type,term.c_str());
vector<node> ans;
if(type==1){
if(term=="T"){
ans=tstu;
}else if(term=="A"){
ans=astu;
}else if(term=="B"){
ans=bstu;
}
//分数降序,id升序
sort(ans.begin(),ans.end(),cmp);
if(ans.size()==0){cout<<"NA"<<endl;continue;}
for(auto st:ans){
printf("%s %d\n",st.id.c_str(),st.score);
}
}else if(type==2){
int cnt=0,total_score=0;
for(auto st:stu){
if(st.site==term){
cnt++;
total_score+=st.score;
}
}
if(cnt==0){cout<<"NA"<<endl;continue;}
printf("%d %d\n",cnt,total_score);
}else if(type==3){
unordered_map<string,int> um;
for(auto st:stu){
if(st.date==term){
um[st.site]++;
}
}
//把结果存入 ans 数组,注意,这里的 id和score不再代表id和分数,而是用他们的类型 string 和 int,来代表 site 和 人数。site 和 人数的排序方式正好与 id和分数的排序方式一样,所以正好可以用同一个 cmp 函数。
vector<node> ans;
for(auto t:um){
node ss;
ss.id=t.first;;
ss.score=t.second;
ans.push_back(ss);
}
sort(ans.begin(),ans.end(),cmp);
if(ans.size()==0){
cout<<"NA"<<endl;
continue;
}
for(int i=0;i<ans.size();i++){
printf("%s %d\n",ans[i].id.c_str(),ans[i].score);
}
}
}
}
int main(){
freopen("data.in","r",stdin);
exec();
return 0;
}
复盘时间:
- 从结果看,pat 接受这种操作,输入用cin,输出用printf,省时间
- string 需要用 cin 输入,但输出可以用 string.c_str() 转为 char[],从而用 printf 输出
- 这个题我开始想的是,大量输入字符串可能会有时间问题,所以决定处理好数据保存结果,再根据请求输出,但从过程来看,type1可以这样做,type2和type3都不行,因为都需要先知道site或者日期才能计算。并且柳神代码来看,即使是type1,每遇到一次查询就处理一次也是来得及的。
题意:
PAT的注册卡包含4部分:
- 第1个字母,代表考试级别,T是顶级,A是甲级,B是乙级
- 第2到第4个数字,代表考试地点,从101到999
- 第5到第10个数字,代表考试日期,格式为yymmdd
- 第11到第13个数字,代表考试者的编号,从000到999
现在给出若干个卡号和卡主的得分,你需要根据不同的查询要求输出不同的统计结果。
第一行给出N,M,分别代表卡的个数和查询个数。
接下来N行,每行给出一个卡号和卡主的得分。
接下来M行,每行给出一个查询,格式为 type term。
type为1,表示输出给定级别的所有考试者,按得分的非升序排列,Term为要查询的级别。
type为2,表示输出给定考试地点的考试总人数,以及他们的总得分,Term为地点编号。
type为3,表示输出给定考试日期的每个考试地点的总人数,Term为测试日期。
对于每个查询,首先打印 Case #: input,#表示查询的索引,从1开始。input是对应查询的输入。
如果 type为1,输出格式与输入相同,也就是卡号 得分。如果有得分相同情况,按卡号的字母表升序,题目保证卡号唯一。
如果 type为2,输出格式为 Nt Ns。Nt是考试总人数,Ns是他们的总得分
如果 type为3,输出格式为 Site Nt,Site为地点编号,Nt为这个地点的总人数。输出必须以Nt的非升序排列,如果有Nt相同的情况,则以地点编号的升序排列。
如果查询的结果为空,则输出NA。