本文为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道题,决定做1054107110821095一共4道。

1054:

放在线性分类下,就要用线性方法做。用 std::map 做起来一看就很简单,为了挑战自己,换一种方法。

大致思路是每个维度(颜色)建立一个散列表,表中存放指向下一个维度的散列表的指针,最后一个维度存放数据。

代码如下:

  1. #include <iostream>
  2. #include <vector>
  3. #include <memory>
  4.  
  5. template <typename T>
  6. using Pointer_vector = std::shared_ptr<std::vector<T>>;
  7.  
  8. int main()
  9. {
  10. int m, n, total;
  11. std::cin >> m >> n;
  12. total = m * n;
  13. using Blue = int;
  14. using Green = Pointer_vector<Blue>;
  15. using Red = Pointer_vector<Green>;
  16. std::vector<Red> data();
  17. for (int cnt = ; cnt != total; ++cnt)
  18. {
  19. int color;
  20. std::cin >> color;
  21. int red = color >> ;
  22. int green = (color >> ) % ;
  23. int blue = color % ;
  24. auto& red_data = data[red];
  25. if (!red_data)
  26. red_data = Red(new std::vector<Green>());
  27. auto& green_data = (*red_data)[green];
  28. if (!green_data)
  29. green_data = Green(new std::vector<Blue>());
  30. auto& blue_data = (*green_data)[blue];
  31. ++blue_data;
  32. }
  33. try
  34. {
  35. for (int r = ; r != ; ++r)
  36. if (data[r])
  37. for (int g = ; g != ; ++g)
  38. if ((*data[r])[g])
  39. for (int b = ; b != ; ++b)
  40. if ((*(*data[r])[g])[b] > total / )
  41. throw (r << ) + (g << ) + b;
  42. }
  43. catch (int res)
  44. {
  45. std::cout << res;
  46. }
  47. }

对于多重循环要 break 的算法我一般用异常来做流控。这是一种备受争议的做法,因此我又想着用输出和 return 替换掉原来的 throw 语句,没想到竟然超时了!加了优化也没用。

不是说 try block会导致性能下降的吗?为什么加了异常处理以后性能反而提高?

想不通。我又用 std::map 实现了一个算法:

  1. #include <iostream>
  2. #include <map>
  3.  
  4. #pragma GCC optimize(O3)
  5.  
  6. int main()
  7. {
  8. int m, n, total;
  9. std::cin >> m >> n;
  10. total = m * n;
  11. std::map<int, int> map;
  12. for (int cnt = ; cnt != total; ++cnt)
  13. {
  14. int color;
  15. std::cin >> color;
  16. ++map[color];
  17. }
  18. for (const auto& pair : map)
  19. if (pair.second > total / )
  20. {
  21. std::cout << pair.first;
  22. return ;
  23. }
  24. return ;
  25. }

一开始当然是没有 #pragma 那一行的,但是超时了,后来加上了才AC。

这道题告诉我们,线性题对时间要求真的很高。或许用 scanf 代替 std::cin 能让原本超时的AC吧,我没试过。

1071:

字符串的线性处理、std::map 的使用,这道题难度就这么多了。代码如下:

  1. #include <iostream>
  2. #include <string>
  3. #include <map>
  4. #include <cctype>
  5.  
  6. int main()
  7. {
  8. std::map<std::string, int> words;
  9. std::string string;
  10. while ()
  11. {
  12. char c = std::cin.get();
  13. if (std::isalnum(c))
  14. string.push_back(std::tolower(c));
  15. else
  16. if (!string.empty())
  17. {
  18. ++words[string];
  19. string.clear();
  20. }
  21. if (c == '\n')
  22. break;
  23. }
  24. auto max = words.cbegin();
  25. for (auto iter = words.cbegin(); iter != words.cend(); ++iter)
  26. if (iter->second > max->second)
  27. max = iter;
  28. std::cout << max->first << ' ' << max->second << std::endl;
  29. }

值得杠一杠的是这道题是不是线性。

首先,输入是O(n),输出是O(1),都在线性范围内。

假设一共有a种单词,对 std::map 的操作是O(a·loga);a种单词连起来的最小长度是O(a·loga),n一定大于这个长度,因此这道题是线性的。

1082:

呵,这道题就是在考数学。但我没有把它放到数学那一类中,因为这是小学数学。

一开始觉得很难,但只要把10000以内的数字怎么读搞清楚了,这道题就差不多了。代码如下:

  1. #include <iostream>
  2. #include <string>
  3. #include <vector>
  4.  
  5. std::vector<std::string> data;
  6.  
  7. const char pinyin[][] =
  8. {
  9. "ling",
  10. "yi",
  11. "er",
  12. "san",
  13. "si",
  14. "wu",
  15. "liu",
  16. "qi",
  17. "ba",
  18. "jiu"
  19. };
  20.  
  21. void chinese(int num)
  22. {
  23. int qian = num / ;
  24. num %= ;
  25. int bai = num / ;
  26. num %= ;
  27. int shi = num / ;
  28. int ge = num % ;
  29. int digit = ;
  30. if (qian)
  31. {
  32. digit = ;
  33. data.push_back(pinyin[qian]);
  34. data.push_back("Qian");
  35. }
  36. if (bai)
  37. {
  38. digit = ;
  39. data.push_back(pinyin[bai]);
  40. data.push_back("Bai");
  41. }
  42. if (shi)
  43. {
  44. if (digit > )
  45. data.push_back(pinyin[]);
  46. digit = ;
  47. data.push_back(pinyin[shi]);
  48. data.push_back("Shi");
  49. }
  50. if (ge)
  51. {
  52. if (digit > )
  53. data.push_back(pinyin[]);
  54. data.push_back(pinyin[ge]);
  55. }
  56. }
  57.  
  58. int main()
  59. {
  60. int num;
  61. std::cin >> num;
  62. if (num == )
  63. {
  64. std::cout << pinyin[];
  65. return ;
  66. }
  67. if (num < )
  68. {
  69. num = -num;
  70. data.push_back("Fu");
  71. }
  72. int yi = num / ;
  73. int wan = num % / ;
  74. int ge = num % ;
  75. int seg = ;
  76. if (yi)
  77. {
  78. seg = ;
  79. data.push_back(pinyin[yi]);
  80. data.push_back("Yi");
  81. }
  82. if (wan)
  83. {
  84. if (wan < && seg > )
  85. data.push_back(pinyin[]);
  86. seg = ;
  87. chinese(wan);
  88. data.push_back("Wan");
  89. }
  90. if (ge)
  91. {
  92. if (ge < && seg > )
  93. data.push_back(pinyin[]);
  94. chinese(ge);
  95. }
  96. int end = data.size() - ;
  97. for (int i = ; i != end; ++i)
  98. std::cout << data[i] << ' ';
  99. std::cout << data[end];
  100. }

这是我第一次用拼音来命名变量。我也不想这样,但谁让这道题中文背景这么明显呢?

1095:

这道题要求模拟车辆进出校园的过程,这类模拟一个过程的题目,我称之为模拟类题。

模拟类题的一个通用方法就是以时间为变量循环,但是这道题写着写着就用上另一种方法了,就是以对象为变量循环,这里的对象就是车辆进出记录。

题目逻辑比较复杂,大致可以分为3个步骤:

第一步,读取所有记录,并按时间顺序排序,然后按记录类型配对;

第二步,读取查询的时间,并模拟车辆进出的过程,这是模拟类题的核心(但在本题中占的比例不大);

第三步,找出最长的停车时间,并输出对应的车牌号(老司机开车!)。

梳理完这堆逻辑以后就直接上代码吧:

  1. #include <iostream>
  2. #include <iomanip>
  3. #include <string>
  4. #include <vector>
  5. #include <map>
  6. #include <algorithm>
  7.  
  8. int read_time()
  9. {
  10. int res, temp;
  11. std::cin >> temp;
  12. res = temp * ;
  13. std::cin.get();
  14. std::cin >> temp;
  15. res += temp * ;
  16. std::cin.get();
  17. std::cin >> temp;
  18. res += temp;
  19. return res;
  20. }
  21.  
  22. void print_time(int time)
  23. {
  24. std::cout << std::setfill('');
  25. std::cout << std::setw() << time / << ':';
  26. time %= ;
  27. std::cout << std::setw() << time / << ':';
  28. std::cout << std::setw() << time % ;
  29. }
  30.  
  31. enum class Status
  32. {
  33. in, out
  34. };
  35.  
  36. struct Record
  37. {
  38. std::string plate;
  39. int time;
  40. Status status;
  41. bool paired = false;
  42. int parking;
  43. };
  44.  
  45. int main()
  46. {
  47. int n, k;
  48. std::cin >> n >> k;
  49. std::vector<Record> records(n);
  50. for (auto& r : records)
  51. {
  52. std::cin >> r.plate;
  53. r.time = read_time();
  54. std::string str;
  55. std::cin >> str;
  56. r.status = str == "in" ? Status::in : Status::out;
  57. }
  58. std::sort(records.begin(), records.end(), [](const Record& _lhs, const Record& _rhs) {
  59. return _lhs.time < _rhs.time;
  60. });
  61. for (auto rec = records.begin(); rec != records.end(); ++rec)
  62. if (rec->status == Status::in)
  63. for (auto iter = rec + ; iter != records.end(); ++iter)
  64. if (iter->plate == rec->plate && iter->status == Status::in)
  65. break;
  66. else if (iter->plate == rec->plate && iter->status == Status::out)
  67. {
  68. rec->paired = iter->paired = true;
  69. rec->parking = iter->time - rec->time;
  70. break;
  71. }
  72.  
  73. auto iter = records.begin();
  74. int count = ;
  75. for (int cnt = ; cnt != k; ++cnt)
  76. {
  77. int time = read_time();
  78. for (; iter != records.end() && iter->time <= time; ++iter)
  79. if (iter->paired && iter->status == Status::in)
  80. ++count;
  81. else if (iter->paired && iter->status == Status::out)
  82. --count;
  83. std::cout << count << std::endl;
  84. }
  85.  
  86. std::map<std::string, int> parking;
  87. for (const auto& rec : records)
  88. if (rec.paired && rec.status == Status::in)
  89. parking[rec.plate] += rec.parking;
  90. int longest = ;
  91. for (const auto& car : parking)
  92. if (car.second > longest)
  93. longest = car.second;
  94. for (const auto& car : parking)
  95. if (car.second == longest)
  96. std::cout << car.first << ' ';
  97. print_time(longest);
  98. }

这道题放在线性类,是因为配对和模拟的算法都是线性的(其实是因为我看到它是模拟类就把它分给线性类了)。

总之,线性类题目难度不高,但坑不少,不仅有各种边界数据,还有卡时间常数的。

PAT甲级题分类汇编——线性的更多相关文章

  1. PAT甲级题分类汇编——杂项

    本文为PAT甲级分类汇编系列文章. 集合.散列.数学.算法,这几类的题目都比较少,放到一起讲. 题号 标题 分数 大意 类型 1063 Set Similarity 25 集合相似度 集合 1067 ...

  2. PAT甲级题分类汇编——图

    本文为PAT甲级分类汇编系列文章. 图,就是层序遍历和Dijkstra这一套,#include<queue> 是必须的. 题号 标题 分数 大意 时间 1072 Gas Station 3 ...

  3. PAT甲级题分类汇编——理论

    本文为PAT甲级分类汇编系列文章. 理论这一类,是让我觉得特别尴尬的题,纯粹是为了考数据结构而考数据结构.看那Author一栏清一色的某老师,就知道教数据结构的老师的思路就是和别人不一样. 题号 标题 ...

  4. PAT甲级题分类汇编——树

    本文为PAT甲级分类汇编系列文章. AVL树好难!(其实还好啦~) 我本来想着今天应该做不完树了,没想到电脑里有一份讲义,PPT和源代码都有,就一遍复习一遍抄码了一遍,更没想到的是编译一遍通过,再没想 ...

  5. PAT甲级题分类汇编——排序

    本文为PAT甲级分类汇编系列文章. 排序题,就是以排序算法为主的题.纯排序,用 std::sort 就能解决的那种,20分都算不上,只能放在乙级,甲级的排序题要么是排序的规则复杂,要么是排完序还要做点 ...

  6. PAT甲级题分类汇编——计算

    本文为PAT甲级分类汇编系列文章. 计算类,指以数学运算为主或为背景的题. 题号 标题 分数 大意 1058 A+B in Hogwarts 20 特殊进制加法 1059 Prime Factors ...

  7. PAT甲级题分类汇编——序言

    今天开个坑,分类整理PAT甲级题目(https://pintia.cn/problem-sets/994805342720868352/problems/type/7)中1051~1100部分.语言是 ...

  8. 【转载】【PAT】PAT甲级题型分类整理

    最短路径 Emergency (25)-PAT甲级真题(Dijkstra算法) Public Bike Management (30)-PAT甲级真题(Dijkstra + DFS) Travel P ...

  9. PAT甲级题解分类byZlc

    专题一  字符串处理 A1001 Format(20) #include<cstdio> int main () { ]; int a,b,sum; scanf ("%d %d& ...

随机推荐

  1. YouTube排名第一的励志英文演讲《Dream(梦想)》

    I don’t know what that dream is that you have, I don't care how disappointing it might have been as ...

  2. 2018-2019-2 网络对抗技术 20165322 Exp7 网络欺诈防范

    2018-2019-2 网络对抗技术 20165322 Exp7 网络欺诈防范 目录 实验原理 实验内容与步骤 简单应用SET工具建立冒名网站 ettercap DNS spoof 结合应用两种技术, ...

  3. ubuntu之路——day10.1 ML的整体策略——正交化

    orthogonalization 正交化的概念就是指,将你可以调整的参数设置在不同的正交的维度上,调整其中一个参数,不会或几乎不会影响其他维度上的参数变化,这样在机器学习项目中,可以让你更容易更快速 ...

  4. 三大框架 之 Hibernate查询(一对多、多对多、查询关系)

    目录 一对多 表之间关系 表之间关系建表原则 一对多关系配置 建立表 建立ORM 添加配置文件 在hibernate.cfg.xml中的标签里,添加核心配置文件 引入工具类 编写测试类 级联操作 什么 ...

  5. 深度学习面试题18:网中网结构(Network in Network)

    目录 举例 参考资料 网中网结构通过多个分支的运算(卷积或池化),将分支上的运算结果在深度上连接 举例 一个3*3*2的张量, 与3个1*1*2的卷积核分别same卷积,步长=1, 与2个2*2*2的 ...

  6. 查看 ssh 攻击 和 攻击成功者

    查看攻击失败记录: grep "Failed password for invalid user admin" /var/log/auth.log 查看攻击成功的记录: grep ...

  7. Firefox disable search in the address bar

    disable search in the address bar Hi oitconz, setting keyword.enabled to false prevents Firefox from ...

  8. Unity3D ACT动作游戏《武士2》项目源码附教程

    武士二源码亲测unity2018.3.6能运行 仅供学习附有教程 教程完整73课,网上大部分一般为65课, 教程大小27GB,mp4格式 整理不易 扫码时备注或说明中留下邮箱 付款后如未回复请至htt ...

  9. C# ffmpeg 视频处理格式转换具体案例

    C# ffmpeg 视频处理格式转换 C# ffmpeg 视频处理格式转换avi到MP4格式 1.代码如下: using System;using System.Diagnostics; namesp ...

  10. centos7搭建maven私服

    Linux:CentOS7安装maven私服Nexus https://blog.csdn.net/plei_yue/article/details/78616267 搭建nexus3版的maven私 ...