【思特奇 ·云上蓝桥-算法训练营】第1周(1~4)

一、跑步训练
问题描述:
小明要做一个跑步训练,初始时,小明充满体力,体力值计为 10000。

如果小明跑步,每分钟损耗 600 的体力。
如果小明休息,每分钟增加 300 的体力。
体力的损耗和增加都是 均匀变化的。

小明打算跑一分钟、休息一分钟、再跑一分钟、再休息一分钟……如此循环。

如果某个时刻小明的体力到达 0,他就停止锻炼, 请问小明在多久后停止锻炼。

为了使答案为整数,请以秒为单位输出答案,答案中只填写数,不填写单位。

答案提交
这是一道结果填空题,你只需要算出结果后提交即可。
本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
答案:3880

解题思路及易错点
1、错误的将问题简化为2分钟消耗300体力,未注意到当体力只剩不到600时,将在小于一分钟之内耗尽(以下为第一次书写错误答案)
 

#include<iostream>
using namespace std;
int main()
{
    int n = 10000;
    float minute = 0;
    for (; n >= 0; minute+=1)
    {
        n -= 600;
        n += 300;
    }
    cout << minute*60;
    return 0;
}

2、将时间以分为单位,计算难度增大(虽然正确,但易错点多,难度大)最终答案以秒为单位,弄巧成拙

#include<iostream>
using namespace std;
int main()
{
	float n = 10000;//体力值必须是float才能是最后一分钟的值是一个小数
	float minute = 0;//分钟必须是float才能解决最后一分钟时间不足问题
	while(n>=0)
	{
		if(n>600)
		{
			n -= 600;
			n += 300;
			minute += 2;
		}
		else
		{
			minute+=n/600;//此处是上面两个铺垫所得
			break;
		}
	}
	cout << minute * 60;//最终答案需要秒
	return 0;
}

3、较为简单的正解

#include <iostream>
using namespace std;
 
int main()
{
	int n = 10000, t = 0;
	
	while(n != 0)
	{
		if(n > 600)
		{
			t += 60;			// 跑一分钟 
			n -= 600;			
			t += 60;			// 休息一分钟 
			n += 300;
		}
		else
		{
			t += n / 10;		// 不足600,跑完就停止锻炼 
			break;
		}
	}
	
	cout << t << endl;
	return 0;
}

二、阶乘约数(未解)
问题描述
定义阶乘 n! = 1 × 2 × 3 × ··· × n。

请问 100! (100 的阶乘)有多少个约数。

答案提交
这是一道结果填空的题,你只需要算出结果后提交即可。
本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

解题思路及难点
 最大的难点是数学(QAQ)认识到一个新的知识点

任意一个正整数 X 都可以表示成若干个质数乘积的形式,即 X = p1α1 ∗ p2α2 …… ∗ pkαk

约数个数 = (a1 + 1)(a2 + 1)……(ak + 1)

正解如下:

#include <iostream>
using namespace std;
 
int p[100];
 
int main()
{
	for (int i = 2; i <= 100; i ++)
	{
		int n = i;
		for (int j = 2; j <= n / j; j ++)
			while(n % j == 0)
			{
				p[j] ++;
				n /= j;
			}
		if(n > 1) p[n] ++;	
	}
	
	long long ans = 1;
	for (int i = 2; i <= 100; i ++)
		if(p[i]) ans *= (p[i] + 1);
 
	cout << ans << endl;
	return 0;	
}

三、出栈次序
问题描述:
        X星球特别讲究秩序,所有道路都是单行线。一个甲壳虫车队,共16辆车,按照编号先后发车,夹在其它车流中,缓缓前行。

路边有个死胡同,只能容一辆车通过,是临时的检查站,如图所示。

  X星球太死板,要求每辆路过的车必须进入检查站,也可能不检查就放行,也可能仔细检查。
  如果车辆进入检查站和离开的次序可以任意交错。那么,该车队再次上路后,可能的次序有多少种?
 为了方便起见,假设检查站可容纳任意数量的汽车。
 显然,如果车队只有1辆车,可能次序1种;2辆车可能次序2种;3辆车可能次序5种。
 现在足足有16辆车啊,亲!需要你计算出可能次序的数目。

解题思路及难点
首先,我们要在理解题意的基础上简化题目内容。

这道题可以在理解栈这一数据结构的基础上简化为:16个元素进出栈后的顺序。

我们不妨先讨论一下较小数量的进出栈问题:

        当元素数量为1时,顺序有一种:1,即f(1)=1

        当元素数量为2时,顺序有两种:12、21,即f(2)=2

        当元素数量为3时,顺序有五种:123、213、321、231、132,即f(3)=5

当元素数量为4时,我们假设们4个元素编号为a,b,c,d, 那么考虑:元素a只可能出现在1号位置,2号位置,3号位置和4号位置(很容易理解,一共就4个位置,比如abcd,元素a就在1号位置)。

分析:

 1) 如果元素a在1号位置,那么只可能a进栈,马上出栈,此时还剩元素b、c、d等待操作,就是子问题f(3);

 2) 如果元素a在2号位置,那么一定有一个元素比a先出栈,即有f(1)种可能顺序(只能是b),还剩c、d,即f(2),根据乘法原理,一共的顺序个数为f(1)* f(2);

 3) 如果元素a在3号位置,那么一定有两个元素比1先出栈,即有f(2)种可能顺序(只能是b、c),还剩d,即f(1),根据乘法原理,一共的顺序个数为f(2) * f(1);

 4) 如果元素a在4号位置,那么一定是a先进栈,最后出栈,那么元素b、c、d的出栈顺序即是此小问题的解,即 f(3);

结合所有情况,即f(4) = f(3) +f(2) * f(1) + f(1) * f(2) + f(3);

为了规整化,我们定义f(0) = 1;于是f(4)可以重新写为:

f(4) = f(0)*f(3) + f(1)*f(2) + f(2) * f(1)+ f(3)*f(0)

然后我们推广到n,推广思路和n=4时完全一样,于是我们可以得到:

f(n) = f(0)*f(n-1) + f(1)*f(n-2) + ... +f(n-1)*f(0)
 代码如下:

#include<iostream>
using namespace std;
int main()
{
	int a[20];
	a[0] = 1;
	a[1] = 1;
	a[2] = 2;
	a[3] = 5;
	int n;
	for (n = 4; n <= 16; n++)
		a[n] = 0;//注意必须给其他数组置0
	for (int i = 4; i <= 16; i++)
	{
		for (int j = 0; j <= i - 1; j++)
		{
			a[i] += a[j] * a[i - j - 1];//代替函数部分
		}
	}
	cout << a[16] << endl;
	return 0;
}

这个题最难的是数学部分,再然后是把函数转化成二重循环的过程。这可能是大部分题目的常态,多练习应该会有改变。

四、哥德巴赫分解(未解)
问题描述:
哥德巴赫猜想认为:不小于4的偶数都可以表示为两个素数的和。

你不需要去证明这个定理,但可以通过计算机对有限数量的偶数进行分解,验证是否可行。

实际上,一般一个偶数会有多种不同的分解方案,我们关心包含较小素数的那个方案。

对于给定数值范围,我们想知道这些包含较小素数方案中最大的素数是多少。

比如,100以内,这个数是19,它由98的分解贡献。

你需要求的是10000以内,这个数是多少?

注意,需要提交的是一个整数,不要填写任何多余的内容(比如,说明性的文字)

解题思路及难点
首先我们需要一个判断是否是质数的函数,再使用两个循环便可以得到答案。
 

#include <iostream>
 
using namespace std;
 
bool is_prime(int num) {
    if (num == 1) return false;
    for (int i = 2; i*i < 1+num; i++)
        if (num % i == 0) return false;
    return true;
}
 
int main() {
    int n;
    cin >> n;
    int m = 0;
    for (int i = n; i > 3; i -= 2) {
        for (int j = 1; 2 * j < i+1; j+=2) {
            if (is_prime(j) && is_prime(i - j)) {
                m = max(m, j);
                break;
            }
        }
    }
    cout << m << endl;
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值