本文为PAT甲级分类汇编系列文章。

集合、散列、数学、算法,这几类的题目都比较少,放到一起讲。

题号 标题 分数 大意 类型
1063 Set Similarity 25 集合相似度 集合
1067 Sort with Swap(0, i) 25 通过与0号元素交换来排序 数学
1068 Find More Coins 30 子集和问题 算法
1070 Mooncake 25 背包问题 算法
1078 Hashing 25 散列 散列
1085 Perfect Sequence 25 符合约束的最大数列长度 集合
1092 To Buy or Not to Buy 20 判断子集 集合
1093 Count PAT's 25 数子串 数学

1063就是 std::set 的使用,1092更水,这两道不做了。

集合-1085:

集合,表示方法多种多样,简单的有用数组表示的并查集,复杂的有基于红黑树的 std::set 。

但我也不知道当时整理的时候怎么把这道题分到集合里来了,但还真挺难说这道题怎么分类的。题目要求从输入数据中找出最大的子列(不一定连续)满足最大值不超过最小值的给定倍数。

实现方法比较简单,先排序,然后对于每个数,找到第一个超过它的倍数的数,迭代器相减一下就是长度。查找要用二分不能用线性,会超时。

 #include <iostream>
#include <vector>
#include <algorithm> int main()
{
long num, para;
std::cin >> num >> para;
std::vector<long> data(num);
for (auto& i : data)
std::cin >> i;
std::sort(data.begin(), data.end());
int max = ;
for (int i = ; i != num; ++i)
{
if (i == || data[i] != data[i - ])
{
auto left = data.begin() + i;
auto right = data.end();
while (left < right)
{
auto mid = left + (right - left) / ;
if (*mid > data[i] * para)
right = mid;
else
left = mid + ;
}
int length = right - data.begin() - i;
if (length > max)
max = length;
if (right == data.end())
break;
}
}
std::cout << max;
}

散列-1078:

纯理论地考察散列知识,用单向平方探测法处理冲突。没什么好说的,就是很标准的散列。数据结构那个题集中有一道hard version,那个真的难。

 #include <iostream>
#include <vector>
#include <cmath> bool is_prime(int _num)
{
if (_num == )
return false;
if (_num > && _num % == )
return false;
int end = std::sqrt(_num);
for (int i = ; i <= end; i += )
if (_num % i == )
return false;
return true;
} int main(int argc, char const *argv[])
{
int m;
std::cin >> m;
while (!is_prime(m))
++m;
std::vector<bool> hash(m);
int n;
std::cin >> n;
for (int i = ; i != n; ++i)
{
try
{
int t;
std::cin >> t;
for (int j = ; j != m; ++j)
{
int h = (t + j * j) % m;
if (hash[h] == )
{
hash[h] = ;
if (i > )
std::cout << ' ';
std::cout << h;
throw ;
}
}
if (i > )
std::cout << ' ';
std::cout << '-';
}
catch (...)
{
;
}
}
return ;
}

数学-1067:

乍一看,完全没有思路。正常排序哪有这么玩的?显然,这道题不考排序,需要一点数学知识把问题转化一下。

对于一个序列,如果值与位置的集合相等,那么一定可以形成若干个环。这道题中需要考虑的是:一元环,即就在应该在的位置上的元素,以及0处于什么样的环中。

自己编几个数据试一下就会发现,需要交换的次数为:

当0处于0号位置时,序列长度+多元环个数-一元环个数(包括0);

当0号位置不是0时,序列长度+多元环个数-一元环个数-2。

 #include <iostream>
#include <utility> int main(int argc, char const *argv[])
{
int n;
std::cin >> n;
std::pair<int, bool> data[n];
int loop = ;
int single = ;
for (auto& i : data)
std::cin >> i.first;
for (int i = ; i != n; ++i)
{
if (data[i].second)
continue;
data[i].second = ;
if (data[i].first == i)
++single;
else
{
++loop;
int t = data[i].first;
while (!data[t].second)
data[t].second = , t = data[t].first;
}
}
if (data[].first == )
std::cout << n + loop - single;
else
std::cout << n + loop - single - ; return ;
}

数学-1093:

要求数“PAT”的个数。如果一个个数的话肯定超时,毕竟题目中都说了数量很大要取模。

正常的算法也不麻烦。先从左向右遍历,数‘P’的数量,在遇到'A'时记录下来;再从右向左遍历,数'T'的数量,也在遇到'A'时记录下来;最后遍历,对每个'A'计算刚才记录的数的乘积并累加。

#include <iostream>
#include <string>
#include <vector> int main()
{
std::string str;
std::cin >> str;
std::vector<int> count_p(str.size());
std::vector<int> count_t(str.size());
long count = ;
for (int i = ; i != str.size(); ++i)
if (str[i] == 'P')
++count;
else if (str[i] == 'A')
count_p[i] = count;
count = ;
for (int i = str.size() - ; i >= ; --i)
if (str[i] == 'T')
++count;
else if (str[i] == 'A')
count_t[i] = count;
count = ;
for (int i = ; i != str.size(); ++i)
if (str[i] == 'A')
count += count_p[i] * count_t[i];
count %= ;
std::cout << count;
}

算法-1070:

贪心算法,在数据结构的Dijkstra中提到过一句,没有系统讲过。但是,这道题的算法相当显然,对每种月饼的单价排序,从高到低选择即可。

 #include <iostream>
#include <iomanip>
#include <vector>
#include <algorithm>
#include <cmath> struct Mooncake
{
double weight;
double price;
}; int main()
{
int num;
double demand;
std::cin >> num >> demand;
std::vector<Mooncake> product(num);
for (auto& p : product)
std::cin >> p.weight;
for (auto& p : product)
std::cin >> p.price;
std::sort(product.begin(), product.end(), [](const Mooncake& lhs, const Mooncake& rhs) {
return lhs.price / lhs.weight > rhs.price / rhs.weight;
});
double total = ;
double profit = ;
for (const auto& p : product)
{
double weight = p.weight > demand - total ? demand - total : p.weight;
total += weight;
profit += weight / p.weight * p.price;
if (std::abs(total - demand) < 0.001)
break;
}
std::cout.setf(std::ios::fixed);
std::cout << std::setprecision() << profit;
}

算法-1068:

这道题压轴,因为我不会。

因为不会,所以瞎写。先写了个递归实现,对每种硬币的数量枚举,其中递归调用函数。遇到有符合要求的组合时,就抛出异常,将硬币组合作为异常参数。结果两个样例竟然都过了,然而提交的结果是4个accept、1个wrong、2个timeout。毕竟递归了,时间复杂度是指数量级的,不超时才怪呢。

想不出更好的算法,去查了答案。这道题是01背包问题,属于动态规划算法,我还没学到,难怪不会做。而且这道题是01背包问题的特殊版,子集和问题,重量和价值都是数的大小。类似的还有著名的两数和、三数和、四数和等。

核心算法是抄的,来自这篇博客

 #include <iostream>
#include <vector>
#include <algorithm>
#include <functional> int main()
{
int num, target;
std::cin >> num >> target;
std::vector<int> coin(num);
for (auto& i : coin)
std::cin >> i;
std::sort(coin.begin(), coin.end(), std::greater<int>());
std::vector<std::vector<bool>> select(num);
for (auto& v : select)
v.resize(target + );
std::vector<int> total(target + );
for (int i = ; i != num; ++i)
for (int j = target; j >= coin[i]; --j)
if (total[j] <= total[j - coin[i]] + coin[i])
{
select[i][j] = true;
total[j] = total[j - coin[i]] + coin[i];
}
if (total[target] != target)
{
std::cout << "No Solution";
return ;
}
int price = target;
int which = num - ;
std::vector<int> found;
while (price)
{
if (select[which][price])
{
found.push_back(coin[which]);
price -= coin[which];
}
--which;
}
int count = ;
for (int i : found)
{
if (count++)
std::cout << ' ';
std::cout << i;
}
}

最后还要说一句,Eva你已经是一个大孩子了,要学会自己解决问题,别总是让我写算法。关键问题是你还老给我出难题。

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

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

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

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

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

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

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

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

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

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

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

  6. PAT甲级题分类汇编——线性

    本文为PAT甲级分类汇编系列文章. 线性类,指线性时间复杂度可以完成的题.在1051到1100中,有7道: 题号 标题 分数 大意 时间 1054 The Dominant Color 20 寻找出现 ...

  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. 熔断机制hystrix

    一.问题产生 雪崩效应:是一种因服务提供者的不可用导致服务调用者的不可用,并将不可用逐渐放大的过程 正常情况下的服务: 某一服务出现异常,拖垮整个服务链路,消耗整个线程队列,造成服务不可用,资源耗尽: ...

  2. MVC框架的主要问题是什么?

    以下是MVC框架的一些主要问题: 对 DOM 操作的代价非常高 程序运行缓慢且效率低下 内存浪费严重 由于循环依赖性,组件模型需要围绕 models 和 views 进行创建

  3. Spring Boot 教程系列学习

    Spring Boot基础教程1-Spring Tool Suite工具的安装 Spring Boot基础教程2-RESTful API简单项目的快速搭建 Spring Boot基础教程3-配置文件详 ...

  4. 乌龙茶生产过程中挥发性成分吲哚的形成 | Formation of Volatile Tea Constituent Indole During the Oolong Tea Manufacturing Process

    吲哚是啥?在茶叶成分中的地位?乌龙茶?香气,重要的前体,比如色氨酸Trp.IAA. Indole is a characteristic volatile constituent in oolong ...

  5. Spring 中开启Mybatis缓存

    mybatis的一级缓存默认是开启的,二级缓存开启的方法: 在每个Mapper.xml文件中加入一个

  6. 伪代码Pseudocode

    程序员之间交流,比划来比划去,与其用产品经理擅长的各种类图.时序图,还不如来一段伪代码来的直接! 伪代码 伪代码(Pseudocode)是一种算法描述语言.使用伪代码的目的是为了使被描述的算法可以容易 ...

  7. Spring AOP(通知、连接点、切点、切面)

    一.AOP术语 通知(Advice)  切面的工作被称为通知.通知定义了切面是什么以及何时使用.除了描述切面要完成的工作,通知还解决了何时执行这个工作的问题.5种通知类型: 前置通知(Before): ...

  8. 无法调用到appcode下的类

    解决方法: 右键 appp_code下的类, 点击 “属性”, 里面 [生成操作] 一项 由内容 改为 编译 即可

  9. IFC构件位置数据与revit模型中对应构件位置数据对比

    IFC构件位置数据与revit模型中对应构件位置数据对比

  10. 【docker 镜像源】解决quay.io和gcr.io国内无法访问的问题

    该问题容易导致image pull back off 错误,应当换源: 微软: https://yeasy.gitbooks.io/docker_practice/install/mirror.htm ...