BUCTOJ - 2023上半年ACM&蓝桥杯每周训练题-1-A~K题C++Python双语版

Posted Tisfy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BUCTOJ - 2023上半年ACM&蓝桥杯每周训练题-1-A~K题C++Python双语版相关的知识,希望对你有一定的参考价值。

文章目录

BUCTOJ - 2023上半年ACM&蓝桥杯每周训练题-1-A~K题C++Python双语版

知识点:题解, BUCTOJ, 中等, 数组, 递归, 动态规划, 循环, 模拟, 素数, 质数, 贪心, 排序, 图论, 图, 迪杰斯特拉, Dijstra, 树, 哈夫曼树, 最小生成树, 归并排序

前言

这篇题解写包含《2023上半年ACM&蓝桥杯每周训练题-1》的A~K题的解析以及C++和Python双版本代码

蒟蒻的我为了《问题 H: 2.5 一场说走就走的旅行》还心血来潮地做了个无人问津的视频,也耽误了不少时间,导致题解现在才完成至这个模样。

PDF不能播放视频,且一段代码可能会分页显示,因此还是比较推荐在网页端看题解的。地址:https://leetcode.letmefly.xyz/2023/02/21/BUCT-BUCT2023LanQiaoWeekly1

若想查找某一知识点,可以直接Ctrl + F。

问题 A: 1.2 神奇兔子数列

题目地址

知识点:数组,递归,动态规划

题目描述

假设第 1 个月有 1 对刚诞生的兔子,第 2 个月进入成熟期,第 3 个月开始生育兔子,而1 对成熟的兔子每月会生 1 对兔子,兔子永不死去……那么,由 1 对初生兔子开始,12 个月后会有多少对兔子呢?
兔子数列即斐波那契数列,它的发明者是意大利数学家列昂纳多·斐波那契(Leonardo Fibonacci,1170—1250)。1202 年,他撰写了《算盘全书(《Liber Abaci》)一书,该书是一部较全面的初等数学著作。书中系统地介绍了印度—阿拉伯数码及其演算法则,介绍了中国的“盈不足术”;引入了负数,并研究了一些简单的一次同余式组。

输入

输出

一个整数(12个月后有多少对兔子)

解题思路

这道题就是要求斐波那契数列的第12项

在计算斐波那契数列的过程中,我们只需要关注连续的3项。

使用两个变量_1和_2代表已经计算出的第一项和第二项,那么要计算出的第三项_3就等于 1 + 2 _1 + _2 1+2

如此往复,更新第一项和第二项为原来的第二项和第三项,就能不断求出新的第三项。

AC代码

C++

#include <bits/stdc++.h>
using namespace std;
#define mem(a) memset(a, 0, sizeof(a))
#define dbg(x) cout << #x << " = " << x << endl
#define fi(i, l, r) for (int i = l; i < r; i++)
#define cd(a) scanf("%d", &a)
typedef long long ll;

int main() 
    ll _1 = 1, _2 = 1, _3;
    for (int i = 3; i <= 12; i++) 
        _3 = _1 + _2;
        _1 = _2, _2 = _3;
    
    cout << _3 << endl;
    return 0;

Python

_1, _2, _3 = 1, 1, ''
for i in range(3, 13):
    _3 = _1 + _2
    _1, _2 = _2, _3
print(_3)

问题 B: 1.3 马克思手稿中的数学题

题目地址

知识点:循环,模拟

题目描述

马克思手稿中有一道趣味数学问题:有 30 个人,其中有男人、女人和小孩,这些人在一家饭馆吃饭花了 50 先令;每个男人花 3 先令,每个女人花 2 先令,每个小孩花 1 先令;问男人、女人和小孩各有几人?

输入

输出

输出所有可能的解
每行三个整数x,y,z(用空格隔开,x代表男人,y代表女人,z代表小孩,按x升序排列):
x y z

解题思路

数据量并不大,我们暴力枚举0到30范围内的所有x、y、z即可。

注意题目中说“其中有男人、女人和小孩”,也就是说每种人都有,不能为0。

AC代码

C++

#include <bits/stdc++.h>
using namespace std;
#define mem(a) memset(a, 0, sizeof(a))
#define dbg(x) cout << #x << " = " << x << endl
#define fi(i, l, r) for (int i = l; i < r; i++)
#define cd(a) scanf("%d", &a)
typedef long long ll;

int main() 
    fi (x, 1, 31) 
        fi (y, 1, 31) 
            fi (z, 1, 31) 
                if (x + y + z == 30 && 3 * x + 2 * y + z == 50) 
                    cout << x << ' ' << y << ' ' << z << endl;
                
            
        
    
    return 0;

Python

for x in range(1, 31):
    for y in range(1, 31):
        for z in range(1, 31):
            if  x + y + z == 30 and 3 * x + 2 * y + z == 50:
                print(x, y, z)

问题 C: 1.4 爱因斯坦的阶梯

题目地址

知识点:模拟

题目描述

爱因斯坦家里有一条长阶梯,若每步跨 2 阶,则最后剩 1 阶;若每步跨 3 阶,则最后剩 2 阶;若每步跨 5 阶,则最后剩 4 阶;若每步跨 6 阶,则最后剩 5 阶。只有每次跨 7 阶,最后才正好 1 阶不剩。请问这条阶梯共有多少阶?

输入

输出

满足题目的最小整数

解题思路

从1开始往上模拟即可

AC代码

C++

#include <bits/stdc++.h>
using namespace std;
#define mem(a) memset(a, 0, sizeof(a))
#define dbg(x) cout << #x << " = " << x << endl
#define fi(i, l, r) for (int i = l; i < r; i++)
#define cd(a) scanf("%d", &a)
typedef long long ll;

int main() 
    int ans = 1;
    while (true) 
        if (ans % 2 == 1 && ans % 3 == 2 && ans % 5 == 4 && ans % 6 == 5 && ans % 7 == 0) 
            cout << ans << endl;
            break;
        
        ans++;
    
    return 0;

Python

ans = 1
while True:
    if ans % 2 == 1 and ans % 3 == 2 and ans % 5 == 4 and ans % 6 == 5 and ans % 7 == 0:
        print(ans)
        break
    ans += 1

问题 D: 1.5 哥德巴赫猜想

题目地址

知识点:模拟、素数/质数

题目描述

哥德巴赫猜想:任一大于 2 的偶数,都可表示成两个素数之和。
验证:2000 以内大于 2 的偶数都能够分解为两个素数之和。

输入

输出

2000 以内大于 2 的偶数被分解的两个素数
按升序排列,第一个素数为最小值
4=2+2
6=3+3
8=3+5
10=3+7
12=5+7
14=3+11
16=3+13

......

解题思路

题目数据范围不大,我们可以先求出2000以内的素数并放入数组和哈希表中,接着对于某个偶数,从最小的素数开始尝试,快速得到 偶数 − 这个素数 偶数-这个素数 偶数这个素数是否也为素数。若是则输出,否则尝试大一点的素数。

AC代码

C++

#include <bits/stdc++.h>
using namespace std;
#define mem(a) memset(a, 0, sizeof(a))
#define dbg(x) cout << #x << " = " << x << endl
#define fi(i, l, r) for (int i = l; i < r; i++)
#define cd(a) scanf("%d", &a)
typedef long long ll;

bool isPrime(int n) 
    int k = sqrt(n);
    for (int i = 2; i <= k; i++) 
        if (n % i == 0) 
            return false;
        
    
    return true;


int main() 
    vector<int> prime;
    unordered_set<int> se;
    for (int i = 2; i <= 2000; i++) 
        if (isPrime(i)) 
            prime.push_back(i);
            se.insert(i);
        
    

    for (int i = 4; i <= 2000; i += 2) 
        for (int t : prime) 
            if (se.count(i - t)) 
                printf("%d=%d+%d\\n", i, t, i - t);
                break;
            
        
    
    return 0;

Python

from math import sqrt


def isPrime(n):
    k = int(sqrt(n))
    for i in range(2, k + 1):
        if n % i == 0:
            return False
    return True


prime = []
se = set()

for i in range(2, 2001):
    if isPrime(i):
        prime.append(i)
        se.add(i)

for i in range(4, 2001, 2):
    for t in prime:
        if i - t in se:
            print(f"i=t+i-t")
            break

问题 E: 2.2 加勒比海盗船

题目地址

知识点:贪心

题目描述

   在北美洲东南部,有一片神秘的海域,那里碧海蓝天、阳光明媚,这正是传说中海盗最活跃的加勒比海(Caribbean Sea)。17 世纪时,这里更是欧洲大陆的商旅舰队到达美洲的必经之地,所以当时的海盗活动非常猖獗,海盗不仅攻击过往商人,甚至攻击英国皇家舰……
   有一天,海盗们截获了一艘装满各种各样古董的货船,每一件古董都价值连城,一旦打碎就失去了它的价值。虽然海盗船足够大,但载重量为 C,每件古董的重量为 wi,海盗们该如何把尽可能多数量的宝贝装上海盗船呢?

输入

请输入问题的组数 m:
m ( 0 < m < 100 )
请输入载重量 c 及古董个数 n:
c n (0 < c, n < 10000)
请输入每个古董的重量,用空格分开:
w1 w2 w3 ... wn  (0 < wi < 100)

输出

能装入的古董最大数量为:
ans

输入样例

1
30 8
4 10 7 11 3 5 14 2

输出样例

5

解题思路

装载数量优先,那必是先装重量小的。

AC代码

C++

#include <bits/stdc++.h>
using namespace std;
#define mem(a) memset(a, 0, sizeof(a))
#define dbg(x) cout << #x << " = " << x << endl
#define fi(i, l, r) for (int i = l; i < r; i++)
#define cd(a) scanf("%d", &a)
typedef long long ll;

int a[10010];

int main() 
    int T;
    cin >> T;
    while (T--) 
        int m, n;
        cin >> m >> n;
        for (int i = 0; i < n; i++) 
            scanf("%d", &a[i]);
        
        sort(a, a + n);
        int ans = 0;
        while (m > 0 && ans < n) 
            if (m >= a[ans]) 
                m -= a[ans++];
            
            else 
                break;
            
        
        cout << ans << endl;
    
    return 0;

Python

T = int(input())
for _ in range(T):
    m, n = map(int, input().split())
    a = list(map(int, input().split()))
    a.sort()
    ans = 0
    while m > 0 and ans < n:
        if m >= a[ans]:
            m -= a[ans]
            ans += 1
        else:
            break
    print(ans)

问题 F: 2.3 阿里巴巴与四十大盗

题目地址

知识点:贪心

题目描述

   有一天,阿里巴巴赶着一头毛驴上山砍柴。砍好柴准备下山时,远处突然出现一股烟尘,弥漫着直向上空飞扬,朝他这儿卷过来,而且越来越近。靠近以后,他才看清原来是一支马队,他们共有四十人,一个个年轻力壮、行动敏捷。一个首领模样的人背负沉重的鞍袋,从丛林中一直来到那个大石头跟前,喃喃地说道:“芝麻,开门吧!”随着那个头目的喊声,大石头前突然出现一道宽阔的门路,于是强盗们鱼贯而入。阿里巴巴待在树上观察他们,直到他们走得无影无踪之后,才从树上下来。他大声喊道:“芝麻,开门吧!”他的喊声刚落,洞门立刻打开了。
   他小心翼翼地走了进去,一下子惊呆了,洞中堆满了财物,还有多得无法计数的金银珠宝,有的散堆在地上,有的盛在皮袋中。突然看见这么多的金银财富,阿里巴巴深信这肯定是一个强盗们数代经营、掠夺所积累起来的宝窟。为了让乡亲们开开眼界,见识一下这些宝物,他想一种宝物只拿一个,如果太重就用锤子凿开,但毛驴的运载能力是有限的,怎么才能用驴子运走最大价值的财宝分给穷人呢?阿里巴巴陷入沉思中……

输入

样例的组数 t
t ( 0 < t < 100 )
宝物数量m和驴子的承载重量 n
m  n ( 0 < m, n < 10000 )
第i个宝物的重量和价值 ( 0 < wi, vi < 100 )

w1  v1  
w2  v2
...
wm  vm

输出

装入宝物的最大价值

输入样例

1
6 19
2 8
6 1
7 9 
4 3 
10 2 
3 4

输出样例

24.6

解题思路

注意题目描述了吗?“如果太重就用锤子凿开”。好家伙,凿开还是宝物的话,那就看哪个宝物的“含金密度”大呗!

接下来我们给每个宝物评分,评分规则是宝物的“密度”( 重量 体积 \\frac重量体积 体积重量

需要注意的是,这道题数据有误,数据中存在重量为0的宝物,也就是说其分数(密度)无限大。注意这时候不能用“重量 * 分数”来计算其总价值了。

还需要注意的是,题目中没有说明输出格式。经测试得知当答案为整数时输出0位小数,答案非整数时输出一些位的小数,完美贴合C++的cout。

还需要注意的是,题目中没有说明多组输入的格式,样例中的多组输入数据之间是有一个空行的,Python选手需要注意

AC代码

C++

#include <bits/stdc++.h>
using namespace std;
#define mem(a) memset(a, 0, sizeof(a))
#define dbg(x) cout << #x << " = " << x <<以上是关于BUCTOJ - 2023上半年ACM&蓝桥杯每周训练题-1-A~K题C++Python双语版的主要内容,如果未能解决你的问题,请参考以下文章

buctoj2021年ACM竞赛班训练题解

BUCTOJ1073

递归的都好难啊!QAQ

2023年上半年PETS5报名及考试时间正式公布

2023年ACM竞赛班 2023.3.20题解

2023上半年数学建模竞赛汇总(报名时间比赛时间难易程度含金量竞赛官网)