大一新生的作业(洛谷P1150,1035,1075)
本帖背景:此帖讲解大一新生团队作业 截止日期10-31 17:09
P1150(Peter的烟)
算法简介
本题主要考察的是模拟算法
模拟算法一般考察一些比较基础的题目,它将生活中的实例融合到了编程题中。
具体要求我们只需要跟着题目一步步走即可。
但是我们要注意模拟算法同样也是很容易出错的,尤其是边界上的问题。
代码
#include<iostream>
using namespace std;
int main()
{
int res = 0;//这个是最终答案,也就是最后能换多少根烟,初始值是0
int n,m;//题目所给的烟和多少根能换一只烟
cin >> n >> m;
int k = 0;//k是临时变量,储存每一次操作后的烟头数量
while(n){//以n作为循环条件,n是目前所存的烟
res += n;//刚开始所有的烟
k += n;//烟头数量(因为n根烟已经全部变成了烟头)
n = k / m;//(用k个烟头能换多少根烟,更新n(目前所存的烟)的值)
k -= n * m;//烟头换烟,还剩下的烟头
}
cout << res << endl;
return 0;
}
注意:在c++中常规的除法是整除操作,比如4/3,这两个整型数相除的结果是1,向下取整,而不是1.33333
P1035(级数求和)
算法简介
本题所考察的也是模拟算法,我们只需要跟着题目所要求的公式把程序写出来就能得到正确的答案
注意:题目中所给的公式包含除法,所以我们应该使用浮点数类型使得所模拟的公式更准确
代码
#include<iostream>
using namespace std;
int k;
int main()
{
cin >> k;//题目中所给的k
double m = 1;//公式中的分子都是1。声明变量为浮点数
int p = 1;//既是项数,也是公式中的分母,比如第一项是1,分母也为1
double sum = 0;//为前p-1项的和,刚开始为0
while(sum <= k){//直到前p-1项的和大于题目所给的k就跳出
sum += m / p;//模拟公式
p++;//项数往后递推
}
cout << p - 1<< endl;//由于sum是前p-1项的和,所以最终答案是p-1
return 0;
}
注意:浮点数除法和上一题的整数除法不同,c++中的除法会保留精度
例如在c++中
- 两个整形数相除,答案为整型数 3/4 = 0 4/3 = 1
- 两个数中有1个是浮点数,则要保留精度 如3/4.0 = 0.75 4/3.0 = 1.33
- 两个数都是浮点数,则同上
P1075(质因数分解)
算法简介
本题考察普通的数学。
质数又被称为素数,是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。
题目的大致意思如21 = 3 * 7(3和7显然都是质数)较大的质数是7,所以输出7
显然题目中所给的数除了能分解成两个素数,不可能有其他的因子(因为质数已经不能再分解)
细节思考
由于题目中n的数据范围太大(2*10 ^ 9),而c++一秒只能计算10 ^ 7~8
为了尽可能地不TLE(时间超限),我们需要想一种优化的方法
首先我们知道,只要能找到较小的素数,我们就能找到较大的素数(因为两者的乘积就是n)
其次,较小的那个质数的平方一定会小于等于n
假如较小的质数是x,x * x<=n
利用反证法证明:
已知x * y = n(x是较小的质数,y是较大的质数)
假设x * x>n 而x < y
根据不等式的传递性 n < x * x < x * y
由于x * y=n 则会出现n < n的矛盾
假设不成立
所以x * x <= n
这样我们的时间复杂度被大大优化了
代码
#include<iostream>
using namespace std;
int n;
int main()
{
cin >> n;//如题意
for(int i = 2; i <= n/i; ++i)//最小的素数从2开始,i<=n/i等价于i * i <= n,像我们刚才证明的那样
if(n % i == 0) {//如果这个数能被整除,说明这个数是较小的质数
cout << n / i << endl; //把另一个较大的质数输出
return 0;//直接结束程序
}
return 0;
}