PAT甲级题分类汇编——线性
本文为PAT甲级分类汇编系列文章。
线性类,指线性时间复杂度可以完成的题。在1051到1100中,有7道:
题号 | 标题 | 分数 | 大意 | 时间 |
1054 | The Dominant Color | 20 | 寻找出现最多的数 | 200ms |
1061 | Dating | 20 | 寻找字符串中相同字符 | 200ms |
1071 | Speech Patterns | 25 | 寻找出现最多的单词 | 300ms |
1077 | Kuchiguse | 20 | 字符串共同后缀 | 150ms |
1082 | Read Number in Chinese | 25 | 中文读数 | 400ms |
1084 | Broken Keyboard | 20 | 比较两序列的差异 | 200ms |
1095 | Cars on Campus | 30 | 模拟车辆进出 | 300ms |
可以看到线性题一般分数不高,一般只有模拟事件的题会出30分,但也不难。
这种题一般一看就会做(最大子列和除外),难度一般在细节处理(所有PAT题都是)和时间常数上。
关于细节处理,分数低的题,本来就简单,做的时候容易想起一些细节问题,在第一次提交之前就处理好了。
关于时间限制,其他题时间限制一般都是400ms,但线性类时间更严格的比较多,这时候就要小心常数了。
仔细阅读了一下7道题,决定做1054、1071、1082和1095一共4道。
1054:
放在线性分类下,就要用线性方法做。用 std::map 做起来一看就很简单,为了挑战自己,换一种方法。
大致思路是每个维度(颜色)建立一个散列表,表中存放指向下一个维度的散列表的指针,最后一个维度存放数据。
代码如下:
- #include <iostream>
- #include <vector>
- #include <memory>
- template <typename T>
- using Pointer_vector = std::shared_ptr<std::vector<T>>;
- int main()
- {
- int m, n, total;
- std::cin >> m >> n;
- total = m * n;
- using Blue = int;
- using Green = Pointer_vector<Blue>;
- using Red = Pointer_vector<Green>;
- std::vector<Red> data();
- for (int cnt = ; cnt != total; ++cnt)
- {
- int color;
- std::cin >> color;
- int red = color >> ;
- int green = (color >> ) % ;
- int blue = color % ;
- auto& red_data = data[red];
- if (!red_data)
- red_data = Red(new std::vector<Green>());
- auto& green_data = (*red_data)[green];
- if (!green_data)
- green_data = Green(new std::vector<Blue>());
- auto& blue_data = (*green_data)[blue];
- ++blue_data;
- }
- try
- {
- for (int r = ; r != ; ++r)
- if (data[r])
- for (int g = ; g != ; ++g)
- if ((*data[r])[g])
- for (int b = ; b != ; ++b)
- if ((*(*data[r])[g])[b] > total / )
- throw (r << ) + (g << ) + b;
- }
- catch (int res)
- {
- std::cout << res;
- }
- }
对于多重循环要 break 的算法我一般用异常来做流控。这是一种备受争议的做法,因此我又想着用输出和 return 替换掉原来的 throw 语句,没想到竟然超时了!加了优化也没用。
不是说 try block会导致性能下降的吗?为什么加了异常处理以后性能反而提高?
想不通。我又用 std::map 实现了一个算法:
- #include <iostream>
- #include <map>
- #pragma GCC optimize(O3)
- int main()
- {
- int m, n, total;
- std::cin >> m >> n;
- total = m * n;
- std::map<int, int> map;
- for (int cnt = ; cnt != total; ++cnt)
- {
- int color;
- std::cin >> color;
- ++map[color];
- }
- for (const auto& pair : map)
- if (pair.second > total / )
- {
- std::cout << pair.first;
- return ;
- }
- return ;
- }
一开始当然是没有 #pragma 那一行的,但是超时了,后来加上了才AC。
这道题告诉我们,线性题对时间要求真的很高。或许用 scanf 代替 std::cin 能让原本超时的AC吧,我没试过。
1071:
字符串的线性处理、std::map 的使用,这道题难度就这么多了。代码如下:
- #include <iostream>
- #include <string>
- #include <map>
- #include <cctype>
- int main()
- {
- std::map<std::string, int> words;
- std::string string;
- while ()
- {
- char c = std::cin.get();
- if (std::isalnum(c))
- string.push_back(std::tolower(c));
- else
- if (!string.empty())
- {
- ++words[string];
- string.clear();
- }
- if (c == '\n')
- break;
- }
- auto max = words.cbegin();
- for (auto iter = words.cbegin(); iter != words.cend(); ++iter)
- if (iter->second > max->second)
- max = iter;
- std::cout << max->first << ' ' << max->second << std::endl;
- }
值得杠一杠的是这道题是不是线性。
首先,输入是O(n),输出是O(1),都在线性范围内。
假设一共有a种单词,对 std::map 的操作是O(a·loga);a种单词连起来的最小长度是O(a·loga),n一定大于这个长度,因此这道题是线性的。
1082:
呵,这道题就是在考数学。但我没有把它放到数学那一类中,因为这是小学数学。
一开始觉得很难,但只要把10000以内的数字怎么读搞清楚了,这道题就差不多了。代码如下:
- #include <iostream>
- #include <string>
- #include <vector>
- std::vector<std::string> data;
- const char pinyin[][] =
- {
- "ling",
- "yi",
- "er",
- "san",
- "si",
- "wu",
- "liu",
- "qi",
- "ba",
- "jiu"
- };
- void chinese(int num)
- {
- int qian = num / ;
- num %= ;
- int bai = num / ;
- num %= ;
- int shi = num / ;
- int ge = num % ;
- int digit = ;
- if (qian)
- {
- digit = ;
- data.push_back(pinyin[qian]);
- data.push_back("Qian");
- }
- if (bai)
- {
- digit = ;
- data.push_back(pinyin[bai]);
- data.push_back("Bai");
- }
- if (shi)
- {
- if (digit > )
- data.push_back(pinyin[]);
- digit = ;
- data.push_back(pinyin[shi]);
- data.push_back("Shi");
- }
- if (ge)
- {
- if (digit > )
- data.push_back(pinyin[]);
- data.push_back(pinyin[ge]);
- }
- }
- int main()
- {
- int num;
- std::cin >> num;
- if (num == )
- {
- std::cout << pinyin[];
- return ;
- }
- if (num < )
- {
- num = -num;
- data.push_back("Fu");
- }
- int yi = num / ;
- int wan = num % / ;
- int ge = num % ;
- int seg = ;
- if (yi)
- {
- seg = ;
- data.push_back(pinyin[yi]);
- data.push_back("Yi");
- }
- if (wan)
- {
- if (wan < && seg > )
- data.push_back(pinyin[]);
- seg = ;
- chinese(wan);
- data.push_back("Wan");
- }
- if (ge)
- {
- if (ge < && seg > )
- data.push_back(pinyin[]);
- chinese(ge);
- }
- int end = data.size() - ;
- for (int i = ; i != end; ++i)
- std::cout << data[i] << ' ';
- std::cout << data[end];
- }
这是我第一次用拼音来命名变量。我也不想这样,但谁让这道题中文背景这么明显呢?
1095:
这道题要求模拟车辆进出校园的过程,这类模拟一个过程的题目,我称之为模拟类题。
模拟类题的一个通用方法就是以时间为变量循环,但是这道题写着写着就用上另一种方法了,就是以对象为变量循环,这里的对象就是车辆进出记录。
题目逻辑比较复杂,大致可以分为3个步骤:
第一步,读取所有记录,并按时间顺序排序,然后按记录类型配对;
第二步,读取查询的时间,并模拟车辆进出的过程,这是模拟类题的核心(但在本题中占的比例不大);
第三步,找出最长的停车时间,并输出对应的车牌号(老司机开车!)。
梳理完这堆逻辑以后就直接上代码吧:
- #include <iostream>
- #include <iomanip>
- #include <string>
- #include <vector>
- #include <map>
- #include <algorithm>
- int read_time()
- {
- int res, temp;
- std::cin >> temp;
- res = temp * ;
- std::cin.get();
- std::cin >> temp;
- res += temp * ;
- std::cin.get();
- std::cin >> temp;
- res += temp;
- return res;
- }
- void print_time(int time)
- {
- std::cout << std::setfill('');
- std::cout << std::setw() << time / << ':';
- time %= ;
- std::cout << std::setw() << time / << ':';
- std::cout << std::setw() << time % ;
- }
- enum class Status
- {
- in, out
- };
- struct Record
- {
- std::string plate;
- int time;
- Status status;
- bool paired = false;
- int parking;
- };
- int main()
- {
- int n, k;
- std::cin >> n >> k;
- std::vector<Record> records(n);
- for (auto& r : records)
- {
- std::cin >> r.plate;
- r.time = read_time();
- std::string str;
- std::cin >> str;
- r.status = str == "in" ? Status::in : Status::out;
- }
- std::sort(records.begin(), records.end(), [](const Record& _lhs, const Record& _rhs) {
- return _lhs.time < _rhs.time;
- });
- for (auto rec = records.begin(); rec != records.end(); ++rec)
- if (rec->status == Status::in)
- for (auto iter = rec + ; iter != records.end(); ++iter)
- if (iter->plate == rec->plate && iter->status == Status::in)
- break;
- else if (iter->plate == rec->plate && iter->status == Status::out)
- {
- rec->paired = iter->paired = true;
- rec->parking = iter->time - rec->time;
- break;
- }
- auto iter = records.begin();
- int count = ;
- for (int cnt = ; cnt != k; ++cnt)
- {
- int time = read_time();
- for (; iter != records.end() && iter->time <= time; ++iter)
- if (iter->paired && iter->status == Status::in)
- ++count;
- else if (iter->paired && iter->status == Status::out)
- --count;
- std::cout << count << std::endl;
- }
- std::map<std::string, int> parking;
- for (const auto& rec : records)
- if (rec.paired && rec.status == Status::in)
- parking[rec.plate] += rec.parking;
- int longest = ;
- for (const auto& car : parking)
- if (car.second > longest)
- longest = car.second;
- for (const auto& car : parking)
- if (car.second == longest)
- std::cout << car.first << ' ';
- print_time(longest);
- }
这道题放在线性类,是因为配对和模拟的算法都是线性的(其实是因为我看到它是模拟类就把它分给线性类了)。
总之,线性类题目难度不高,但坑不少,不仅有各种边界数据,还有卡时间常数的。
PAT甲级题分类汇编——线性的更多相关文章
- PAT甲级题分类汇编——杂项
本文为PAT甲级分类汇编系列文章. 集合.散列.数学.算法,这几类的题目都比较少,放到一起讲. 题号 标题 分数 大意 类型 1063 Set Similarity 25 集合相似度 集合 1067 ...
- PAT甲级题分类汇编——图
本文为PAT甲级分类汇编系列文章. 图,就是层序遍历和Dijkstra这一套,#include<queue> 是必须的. 题号 标题 分数 大意 时间 1072 Gas Station 3 ...
- PAT甲级题分类汇编——理论
本文为PAT甲级分类汇编系列文章. 理论这一类,是让我觉得特别尴尬的题,纯粹是为了考数据结构而考数据结构.看那Author一栏清一色的某老师,就知道教数据结构的老师的思路就是和别人不一样. 题号 标题 ...
- PAT甲级题分类汇编——树
本文为PAT甲级分类汇编系列文章. AVL树好难!(其实还好啦~) 我本来想着今天应该做不完树了,没想到电脑里有一份讲义,PPT和源代码都有,就一遍复习一遍抄码了一遍,更没想到的是编译一遍通过,再没想 ...
- PAT甲级题分类汇编——排序
本文为PAT甲级分类汇编系列文章. 排序题,就是以排序算法为主的题.纯排序,用 std::sort 就能解决的那种,20分都算不上,只能放在乙级,甲级的排序题要么是排序的规则复杂,要么是排完序还要做点 ...
- PAT甲级题分类汇编——计算
本文为PAT甲级分类汇编系列文章. 计算类,指以数学运算为主或为背景的题. 题号 标题 分数 大意 1058 A+B in Hogwarts 20 特殊进制加法 1059 Prime Factors ...
- PAT甲级题分类汇编——序言
今天开个坑,分类整理PAT甲级题目(https://pintia.cn/problem-sets/994805342720868352/problems/type/7)中1051~1100部分.语言是 ...
- 【转载】【PAT】PAT甲级题型分类整理
最短路径 Emergency (25)-PAT甲级真题(Dijkstra算法) Public Bike Management (30)-PAT甲级真题(Dijkstra + DFS) Travel P ...
- PAT甲级题解分类byZlc
专题一 字符串处理 A1001 Format(20) #include<cstdio> int main () { ]; int a,b,sum; scanf ("%d %d& ...
随机推荐
- YouTube排名第一的励志英文演讲《Dream(梦想)》
I don’t know what that dream is that you have, I don't care how disappointing it might have been as ...
- 2018-2019-2 网络对抗技术 20165322 Exp7 网络欺诈防范
2018-2019-2 网络对抗技术 20165322 Exp7 网络欺诈防范 目录 实验原理 实验内容与步骤 简单应用SET工具建立冒名网站 ettercap DNS spoof 结合应用两种技术, ...
- ubuntu之路——day10.1 ML的整体策略——正交化
orthogonalization 正交化的概念就是指,将你可以调整的参数设置在不同的正交的维度上,调整其中一个参数,不会或几乎不会影响其他维度上的参数变化,这样在机器学习项目中,可以让你更容易更快速 ...
- 三大框架 之 Hibernate查询(一对多、多对多、查询关系)
目录 一对多 表之间关系 表之间关系建表原则 一对多关系配置 建立表 建立ORM 添加配置文件 在hibernate.cfg.xml中的标签里,添加核心配置文件 引入工具类 编写测试类 级联操作 什么 ...
- 深度学习面试题18:网中网结构(Network in Network)
目录 举例 参考资料 网中网结构通过多个分支的运算(卷积或池化),将分支上的运算结果在深度上连接 举例 一个3*3*2的张量, 与3个1*1*2的卷积核分别same卷积,步长=1, 与2个2*2*2的 ...
- 查看 ssh 攻击 和 攻击成功者
查看攻击失败记录: grep "Failed password for invalid user admin" /var/log/auth.log 查看攻击成功的记录: grep ...
- Firefox disable search in the address bar
disable search in the address bar Hi oitconz, setting keyword.enabled to false prevents Firefox from ...
- Unity3D ACT动作游戏《武士2》项目源码附教程
武士二源码亲测unity2018.3.6能运行 仅供学习附有教程 教程完整73课,网上大部分一般为65课, 教程大小27GB,mp4格式 整理不易 扫码时备注或说明中留下邮箱 付款后如未回复请至htt ...
- C# ffmpeg 视频处理格式转换具体案例
C# ffmpeg 视频处理格式转换 C# ffmpeg 视频处理格式转换avi到MP4格式 1.代码如下: using System;using System.Diagnostics; namesp ...
- centos7搭建maven私服
Linux:CentOS7安装maven私服Nexus https://blog.csdn.net/plei_yue/article/details/78616267 搭建nexus3版的maven私 ...