一、跑步训练
问题描述:
小明要做一个跑步训练,初始时,小明充满体力,体力值计为 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;
}