第一题
小多有若干个机器学习模型,每个模型都需要先经过训练再经过运行验证才能完成。小多只有一台训练机,每次只能训练一个模型,每个模型训练完成后可以立即运行,但多个模型可以同时运行。请你求出小多完成所有模型的最短时间。
第一行输入模型的个数,从第二行开始,第一个数是模型运行的时间,第二个数是模型训练的时间,输出所有模型完成的最短时间。模型个数,训练时间,运行时间均处于[1, 100000]内。
示例1
输入:
3
4 1
2 5
3 100
输出:
108
//按照132的顺序训练,第1个模型完成的时间为5,第3个模型完成的时间为104,第2个模型完成的时间为108
解答:
本题使用模拟做法,所有的模型都要逐个经过训练,因此总训练时间是不变的,所以要尽可能减少运行时间,由于运行可以同时进行,所以需要将模型按照运行时间从大到小排序,逐个计算当前模型的完成时间,取最小值。这题AC一直卡在60%,后来发现是trainTime溢出了,换成long long就好了。
代码:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// 为了看中间变量而设计的函数,不需要
// void printPair(vector<pair<int, int>> &nums);
// 自定义排序,从大到小排
bool mySort(pair<int, int> a, pair<int, int> b)
{
return a.first > b.first;
}
// 输出最小运行时间
void getTime(vector<pair<int, int>> &experiment, int n)
{
sort(experiment.begin(), experiment.end(), mySort); // 将输入按运行时间从大到小排序
long long trainTime = 0, maxTime = 0;
for (auto ite = experiment.begin(); ite != experiment.end(); ite++)
{
trainTime += ite->second; // 计算每个模型的训练开始时间
maxTime = max(maxTime, trainTime + ite->first); // 取最大的运行结束时间
}
// printPair(experiment);
cout << maxTime << endl;
}
// void printPair(vector<pair<int, int>> &nums) {
// for (auto ite = nums.begin(); ite != nums.end(); ite++) {
// cout << ite->first << ite->second << endl;
// }
// }
int main()
{
int n;
cin >> n;
vector<pair<int, int>> experiment; // 使用pair数组储存输入的数据
for (int i = 0; i < n; i++)
{
int a, b;
cin >> a >> b;
experiment.push_back(make_pair(a, b));
}
getTime(experiment, n);
system("pause");
return 0;
}
第二题
输入一个整数数组,第一步取相邻两个数的绝对值,得到一个新的数组。如果这个新的数组中的数字都是连续的,就输出YES、最大值和最小值;否则就输出NO、数字的最大重复次数和缺少的数字个数。
示例1
输入:
4
4 1 3 2
输出:
YES
1 3
示例2
输入:
4
4 3 2 1
输出:
NO
3 0
解答:
这道题其实也可以使用模拟解法:
- 将输入的数字两两取绝对值,再排序,获得新的数组;
- 使用unordered_map统计每个数字出现的次数;
- 遍历unordered_map,获得最大重复次数和所有重复的次数;
- 判断条件为“最大重复次数=1 && 所有重复次数 = 0 && 最大最小值的差 = 数组长度”
- 如果输出NO,求缺少的数字个数是关键,缺少的数字个数 = 最大值 - 最小值 + 1 - 数组长度 + 所有重复次数
代码:
#include <iostream>
#include <vector>
#include <unordered_map>
#include <algorithm>
using namespace std;
vector<int> getNums(vector<int> &nums, int n) {
vector<int> res;
for (int i = 0; i < n - 1; i++) {
res.push_back(nums[i + 1] - nums[i]); // 获得新的数组
}
sort(res.begin(), res.end()); // 数组排序,方便后面计算
return res;
}
void isValid(vector<int> &nums, int n) {
unordered_map<int, int> mp;
for (int num : nums) {
mp[num]++; // 统计数字出现的次数
}
int maxCount = 0; // 最大出现次数
int count = 0; // 总重复次数
for (auto ite = mp.begin(); ite != mp.end(); ite++) {
if (ite->second > 1) {
maxCount = max(maxCount, ite->second); // 更新最大出现次数
count += ite->second - 1; // 更新总重复次数
}
}
if (maxCount == 1 && count == 0 && nums[n - 1] - nums[0] + 1 == n) {
cout << "YES" << endl;
cout << nums[0] << " " << nums[n - 1] << endl;
}
else {
cout << "NO" << endl;
cout << maxCount << " " << nums[n - 1] - nums[0] + 1 - n + count << endl;
}
}
int main() {
int n;
cin >> n;
vector<int> nums;
for (int i = 0; i < n; i++) {
int num;
cin >> num;
nums.push_back(num);
}
vector<int> tmp = getNums(nums, n);
isValid(tmp, n - 1);
return 0;
}
第三题
把小说看做由N个情节组成,每个情节可用非空字符串
S
i
S_i
Si表示,
S
i
S_i
Si的长度不大于3,可以删除任意情节(0个或多个),不可以打乱字符串顺序,使得剩余情节按顺序构成回文。
示例1
输入:
4
ab
a
abc
ba
输出:
YES // 删除a和abc后,剩余字符串为abba,构成回文
第四题
现有一个林场,要把部分树移植到别处,使得移植之后,高度最高的树占所有树的一半以上。每棵树有高度和移植时间两个属性,求最短的移植时间。
输入的第一行是林场数目的数目,第二行开始,第一个数字是树的高度,第二个数字是移植时间。
示例1
2
1 3
2 2
输出
2 //最高树高度为2,有1棵,未超过总数的一半,所以移植走高度为2的树,剩余最高的树高度为1,耗时为3
示例2
输入
3
1 1
2 2
2 2
输出
0 //最高的树高度为2,有两棵,超过总数一半,无需移植
示例3
输入
6
1 5
1 5
2 4
2 3
3 1
3 2
输出
8