此题是去年12月份甲级PAT没有拿到全分的题目。当时最后两个点没有过,所以最可能拿满分的一次机会白白流失掉了。
当初最后两个点是因为超时,一时半会没想到如何去优化。回来以后也没有花时间再去解决这个TLE问题。
昨天晚上突然想到这题,抽时间写了一下,花了2个小时还是最后两个点没有过,百思不得其解。
今天解决了这个问题,觉得有毒。
网上各大博客都没有着重点出如何解决这个TLE(超时)问题,也很有可能是因为我太久没有做题忘记了这些做题常识等等原因吧。遂在此记录一下此题之外,兴许能够帮到同在苦恼第三个点总是过不了的同学人们吧。
题意:N个卡号(N最大10e4)M次询问(M最大10e2)。对于每个卡号,由级别(首字母)、地区号(三位数)、日期(六位数)、用户id(3位数)(没用到)的信息组成。然后给出M个询问,询问分成三种,第一种就是输出所有人的卡号和成绩(降序);第二种是输出指定地点的人数情况与总分;第三种是给出某日期,输出此日下,各个地点的考试人数(降序)。
思路:这么一看其实很明显,这题在考场上就是看你的细致模拟、编码速度。这些相信都不是问题。而解决问题,不管是那种询问,都遵循的是先遍历一遍题目给出的卡号清单,更具要求筛选出我们需要的卡号,将这些筛选出的人根据特定的排序要求进行排序并输出结果即可。
其中要注意的是,第一种询问和第三种询问都是需要按照一定优先级进行排序操作的——数据量是1W而查询量是100,讲道理肯定是不会超时的。但是在提交的时候却发生了超时情况是什么原因呢?
难点:
- 第一种询问和第二种询问撰写都比较简单,复杂度分别是O(NlogN)以及O(N)也不会有太大问题。但第三种询问,需要将所有卡号根据查询给出的日期,将此日卡号挑出并根据对应的地址进行归类!如此一来,多数人会想到用map来建立“地址映射”,但这样就会TLE。仔细看,题目给出的程序运行时间限制为200ms,而一般的题目是1000ms。map的底层是由红黑树实现的,红黑树作为一棵树的查询复杂度就是(logN),以及要具备红黑树的特性其时空会带来额外的消耗。如果用map进行映射,整道题的复杂度虽然是O(N+M(NlogN+NlogN+N))(读取数据、M次查询(地址查询、排序、输出))但是却会超时。所以,第一点就是要用unordered_map来代替map。unordered_map也是用于映射,但底层由哈希实现,单次查询速度为O(1),可以将时间降低为O(N+M(1+NlogN+N)).
- 然鹅我本来就是用unordered_map也超时了?,第三个数据点死活过不了!第四个数据点要靠运气,有时候150ms有时候197ms有时候过不了,但是柳神等人的代码第四个数据点是50ms,比我快了三倍!!!看了诸多博客,完全get不到自己为什么会超时。第一点就是大部分博客都会提到的地方。一度怀疑是因为vector的size、string流、cin、局部变量回收过程、switch比不过if等奇奇怪怪的效率问题,已经神经质了......突然瞄到柳神以及其他人AC的代码中,在最后的O(N)的输出环节中,用的并不是cout而是printf!!!!!搞了半天不是cin的速度慢是cout的输出慢,猪脑子居然没想到!!!改了这个地方直接就A了。。。记住了,cout居然比printf输出慢了三倍!
代码上嘛我写的一般般,没有柳神那么优秀。。。在准备PAT的时候,一些基本的库函数比如stoi(string转int)、string的成员函数c_str(string转char数组)、unordered_map(常用的map的替代者)都要去看,都是基本操作,别忘了。
Code:
#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
#define inf 10009
#define INF 0x3f3f3f3f
#define loop(x,y,z) for(x=y;x<z;x++)
int n,m;
struct Info
{
string card;
int value;
string level;
string site;
string date;
void set(string s,int v)
{
value=v;
card=s;
level=s.substr(0,1);
site=s.substr(1,3);
date=s.substr(4,6);
}
}info[inf];
void readData()
{
int i,j;
int value;
string s;
loop(i,0,n)
{
cin>>s>>value;
info[i].set(s,value);
}
}
bool cmp1(const int& i,const int &j)//ÌáÎÊ1µÄÅÅÐò
{
if(info[i].value==info[j].value)return info[i].card<info[j].card;
return info[i].value>info[j].value;
}
struct Type3
{
string site;
int num;
Type3(string s)
{
site=s;
num=1;
}
bool operator<(const Type3&t)const
{
if(num==t.num)return site<t.site;
return num>t.num;
}
};
int main()
{
int i,j,k;
cin>>n>>m;
readData();//¶ÁÈ¡
loop(k,1,m+1)
{
int type;
cin>>type;
switch(type)
{
case 1:{
string level;
cin>>level;
vector<int>cache;
cache.clear();
loop(i,0,n)
if(info[i].level==level)cache.push_back(i);
sort(cache.begin(),cache.end(),cmp1);
//print
cout<<"Case "<<k<<": "<<type<<' '<<level<<endl;
if(!cache.size())cout<<"NA"<<endl;
else{
int len=cache.size();
loop(i,0,len)
printf("%s %d\n",info[cache[i]].card.c_str(),info[cache[i]].value);//改成这个才不会超市
//cout<<info[cache[i]].card<<' '<<info[cache[i]].value<<endl;
}
break;
}
case 2:{
string site;
cin>>site;
int num=0;
int sum=0;
loop(i,0,n)
if(info[i].site==site)
{
num++;
sum+=info[i].value;
}
//print
cout<<"Case "<<k<<": "<<type<<' '<<site<<endl;
if(num)
cout<<num<<' '<<sum<<endl;
else
cout<<"NA"<<endl;
break;
}
case 3:{
string date;
cin>>date;
vector<Type3>cache;
unordered_map<string,int>mp;
loop(i,0,n)
if(info[i].date==date)
{
string &site=info[i].site;
if(mp.count(site))cache[mp[site]].num++;
else {
mp[site]=cache.size();
Type3 t(site);
cache.push_back(t);
}
}
sort(cache.begin(),cache.end());
//print
cout<<"Case "<<k<<": "<<type<<' '<<date<<endl;
if(!cache.size())cout<<"NA"<<endl;
else{
int len=cache.size();
loop(i,0,len)
printf("%s %d\n",cache[i].site.c_str(),cache[i].num);//改成这个才不会超市
//cout<<cache[i].site<<' '<<cache[i].num<<endl;
}
break;
}
default:break;
}
}
return 0;
}