1153 Decode Registration Card of PAT 25

这篇博客讲述了作者在解决PAT模拟题时遇到的问题,主要涉及字符串处理和效率优化。作者最初使用数组统计个数,但因超时问题转向使用unordered_map。尽管如此,代码仍然超时,最终发现是由于cout造成的输出延迟。解决方案是使用cin输入,printf输出,以节省时间。博客还分析了不同查询类型对数据处理的需求,并提供了最终代码。
摘要由CSDN通过智能技术生成

这题是一个需要处理字符串的模拟题。

下面是我最开始写出来的代码。

#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这种东西?

或者是,应该对数据进行预处理,而不是每来一个请求计算一次?

不对,在计算某天的考点数据时,必须要先获得日期才有意义,不然会做大量可能无用的计算(比如把出现过的所有日期都算一遍)。

想不到办法,就去看了柳神的代码。

发现他用了两个加速技巧:

  1. unordered_map
  2. 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;
}

复盘时间:

  1. 从结果看,pat 接受这种操作,输入用cin,输出用printf,省时间
  2. string 需要用 cin 输入,但输出可以用 string.c_str() 转为 char[],从而用 printf 输出
  3. 这个题我开始想的是,大量输入字符串可能会有时间问题,所以决定处理好数据保存结果,再根据请求输出,但从过程来看,type1可以这样做,type2和type3都不行,因为都需要先知道site或者日期才能计算。并且柳神代码来看,即使是type1,每遇到一次查询就处理一次也是来得及的。

题目

题意:

PAT的注册卡包含4部分:

  1. 第1个字母,代表考试级别,T是顶级,A是甲级,B是乙级
  2. 第2到第4个数字,代表考试地点,从101到999
  3. 第5到第10个数字,代表考试日期,格式为yymmdd
  4. 第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。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值