爆刷PAT(甲级)——之【1153】 Decode Registration Card of PAT (25 分)——模拟细节题(如何解决超时问题!)

此题是去年12月份甲级PAT没有拿到全分的题目。当时最后两个点没有过,所以最可能拿满分的一次机会白白流失掉了。

当初最后两个点是因为超时,一时半会没想到如何去优化。回来以后也没有花时间再去解决这个TLE问题。

昨天晚上突然想到这题,抽时间写了一下,花了2个小时还是最后两个点没有过,百思不得其解。

今天解决了这个问题,觉得有毒。

网上各大博客都没有着重点出如何解决这个TLE(超时)问题,也很有可能是因为我太久没有做题忘记了这些做题常识等等原因吧。遂在此记录一下此题之外,兴许能够帮到同在苦恼第三个点总是过不了的同学人们吧。

 

题意:N个卡号(N最大10e4)M次询问(M最大10e2)。对于每个卡号,由级别(首字母)、地区号(三位数)、日期(六位数)、用户id(3位数)(没用到)的信息组成。然后给出M个询问,询问分成三种,第一种就是输出所有人的卡号和成绩(降序);第二种是输出指定地点的人数情况与总分;第三种是给出某日期,输出此日下,各个地点的考试人数(降序)

 

思路:这么一看其实很明显,这题在考场上就是看你的细致模拟、编码速度。这些相信都不是问题。而解决问题,不管是那种询问,都遵循的是先遍历一遍题目给出的卡号清单,更具要求筛选出我们需要的卡号,将这些筛选出的人根据特定的排序要求进行排序并输出结果即可。

其中要注意的是,第一种询问和第三种询问都是需要按照一定优先级进行排序操作的——数据量是1W而查询量是100,讲道理肯定是不会超时的。但是在提交的时候却发生了超时情况是什么原因呢?

 

难点:

  1. 第一种询问和第二种询问撰写都比较简单,复杂度分别是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)).
  2. 然鹅我本来就是用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;
}

 

  • 10
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值