试题A:日期统计
【问题描述】
小蓝现在有一个长度为 100 的数组,数组中的每个元素的值都在 0 到 9 的范围之内。数组中的元素从左至右如下所示:
5 6 8 6 9 1 6 1 2 4 9 1 9 8 2 3 6 4 7 7 5 9 5 0 3 8 7 5 8 1 5 8 6 1 8 3 0 3 7 9 2 7 0 5 8 8 5 7 0 9 9 1 9 4 4 6 8 6 3 3 8 5 1 6 3 4 6 7 0 7 8 2 7 6 8 9 5 6 5 6 1 4 0 1 0 0 9 4 8 0 9 1 2 8 5 0 2 5 3 3
现在他想要从这个数组中寻找一些满足以下条件的子序列:
1.子序列的长度为 8;
2.这个子序列可以按照下标顺序组成一个 yyyymmdd 格式的日期,并且要求这个日期是 2023 年中的某一天的日期,例如 20230902,20231223。
yyyy 表示年份,mm 表示月份,dd 表示天数,当月份或者天数的长度只有一位时需要一个前导零补充。
请你帮小蓝计算下按上述条件一共能找到多少个不同 的 2023 年的日期。
对于相同的日期你只需要统计一次即可。
【解题】
注意子序列的定义就好,子序列是序列的一部分,可以通过从原序列中删除一些(或不删除)元素但不改变其余元素的顺序得到。重点是顺序不变,以子序列的长度为条件,从头开始遍历数据。
(1)循环遍历,找到2023,i=0开始遍历,找到2,从此位置的下一个数开始遍历,找到0,依次类推,找到2和3
int find_2023(vector<int> arr){
for(int i = 0 ; i < arr.size() - 7; i++)
{
if(arr[i] == 2){
for(int j = i + 1;j < arr.size() - 6; j++){
if(arr[j] == 0){
for(int k = j + 1; k < arr.size() - 5; k++){
if(arr[k] == 2){
for(int l = k + 1; l < arr.size() - 4; l++){
if(arr[l] == 3){
return l + 1 ;
}
}
}
}
}
}
}
}
}
2.month:存放月份的天数
month_checked:检查是否已经组合成功
mm:先找到第一个数小于2,在第二个变成十位数,如何是有效月份,就将month_checked记为1,
dd:先找到第一个数小于2,在第二个变成十位数,如何是有效日期,是就将子序列添加到vector
#include <iostream>
#include <vector>
#include <set>
using namespace std;
int find_2023(vector<int> arr){
for(int i = 0 ; i < arr.size() - 7; i++)
{
if(arr[i] == 2){
for(int j = i + 1;j < arr.size() - 6; j++){
if(arr[j] == 0){
for(int k = j + 1; k < arr.size() - 5; k++){
if(arr[k] == 2){
for(int l = k + 1; l < arr.size() - 4; l++){
if(arr[l] == 3){
return l + 1 ;
}
}
}
}
}
}
}
}
}
int main() {
vector<int> arr = {5, 6, 8, 6, 9, 1, 6, 1, 2, 4, 9, 1, 9, 8, 2, 3, 6, 4, 7, 7, 5, 9, 5, 0, 3, 8, 7, 5, 8, 1, 5, 8, 6, 1, 8, 3, 0, 3, 7, 9, 2,
7, 0, 5, 8, 8, 5, 7, 0, 9, 9, 1, 9, 4, 4, 6, 8, 6, 3, 3, 8, 5, 1, 6, 3, 4, 6, 7, 0, 7, 8, 2, 7, 6, 8, 9, 5, 6, 5, 6, 1, 4, 0, 1,
0, 0, 9, 4, 8, 0, 9, 1, 2, 8, 5, 0, 2, 5, 3, 3};
vector<int> month = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
vector<int> month_checked(12, 0);
set<int> unique_set;
for (int a = find_2023(arr); a < arr.size() - 3; a++)
{
if (arr[a] < 2)
{
for (int b = a + 1; b < arr.size() - 2; b++)
{
int month1 = arr[a] * 10 + arr[b];
if (0 < month1 && month1 < 13 && month_checked[month1 - 1] == 0)
{
month_checked[month1 - 1] = 1;
for (int c = b + 1; c < arr.size() - 1; c++)
{
if (arr[c] < 4)
{
for (int d = c + 1; d < arr.size(); d++)
{
int day1 = arr[c] * 10 + arr[d];
if (0 < day1 && day1 <= month[month1 - 1])
{
unique_set.insert(arr[a] * 1000 + arr[b] * 100 + arr[c] * 10 + arr[d]);
}
}
}
}
}
}
}
}
// 输出唯一日期的数量
cout << unique_set.size() << endl;
return 0;
}
set容器内部的元素唯一:
试题C:冶炼金属
【问题描述】
小蓝有一个神奇的炉子用于将普通金属 O 冶炼成为一种特殊金属 X。这个炉子有一个称作转换率的属性 V,V 是一个正整数,这意味着消耗 V 个普通金属 O 恰好可以冶炼出一个特殊金属 X,当普通金属 O 的数目不足 V 时,无法继续冶炼。
现在给出了 N 条冶炼记录,每条记录中包含两个整数 A 和 B,这表示本次投入了 A 个普通金属 O,最终冶炼出了 B 个特殊金属 X。每条记录都是独立的,这意味着上一次没消耗完的普通金属 O 不会累加到下一次的冶炼当中。根据这 N 条冶炼记录,请你推测出转换率 V 的最小值和最大值分别可能是多少,题目保证评测数据不存在无解的情况。
【输入格式】
第一行一个整数 N,表示冶炼记录的数目。
接下来输入 N 行,每行两个整数 A、B,含义如题目所述。
【输出样式】
输出两个整数,分别表示 V 可能的最小值和最大值,中间用空格分开。
【样例输入】
3
75 3
53 2
59 2
【样例输出】
20 2
【解题】
对一行冶炼记录来说,合成金属X,要么刚好消耗完 满足 等式 A/B=V,要么 剩余的金属O < V 即满足不等式 A - B*V < V => V > A / (B+1)
由不等式可知V_max是刚好消耗完的时候,V_min是刚好少一块金属O就能合成金属X,即不等式 A/B >= v > A/(B+1)
#include <iostream>
#include <climits>
using namespace std;
int main() {
int n;
int Vmin_max = 0;
int Vmax_min = INT_MAX; // 使用<climits>中定义的最大int值
int vmin, vmax;
int a, b;
cin >> n;
for(int i = 0; i < n; i++){
cin >> a >> b;
vmax = a / b;
vmin = a / (b + 1) + 1;
if(vmax < Vmax_min){
Vmax_min = vmax;
}
if (vmin > Vmin_max){
Vmin_max = vmin;
}
}
cout << Vmin_max << " " << Vmax_min << endl;
return 0;
}