一、 级数求和
题目描述
已知:。显然对于任意一个整数 k,当 n 足够大的时候,。
现给出一个整数 k,要求计算出一个最小的 n,使得 。
输入格式
一个正整数 k。
输出格式
一个正整数 n。
样例 #1
样例输入 #1
1
样例输出 #1
2
提示
【数据范围】
对于 100% 的数据,。
我的答案
#include<iostream>
using namespace std;
int main(){
int k,n;
double s=0;
double Sn=0;
cin>>k;
for(n=1;;n++)//不能写成int n=1,要不然n被声明两次会导致错误
{
s+=1;
Sn+=1/s;
if(Sn>k)
{
break;
}
}
cout<<n;
return 0;
}
简化代码
#include <iostream>
using namespace std;
int main() {
int k;
cin >> k; // 输入k
int n = 1, sum = 1; // 初始化n和Sn
while (sum <= k) { // 当Sn <= k时,继续累加
n++;
sum += n;
}
cout << n << endl; // 输出最小的n
return 0;
}
该算法通过不断累加求出最小的n,使得Sn > k。其时间复杂度为O(sqrt(k))。
优化性能
#include <iostream>
#include <cmath>
using namespace std;
int main() {
int k;
cin >> k; // 输入k
int n = ceil((-1.0 + sqrt(1 + 8.0 * k)) / 2); // 计算最小的n,向上取整
cout << n << endl; // 输出最小的n
return 0;
}
根据等差数列求和公式Sn=n(n+1)/2,我们可以得到n = (-1 + sqrt(1 + 8*k)) / 2。因为我们只需要整数解,所以可以向下取整得到最小的满足Sn>k的整数n。这个算法的时间复杂度为O(1),比之前的算法更加高效。这里引用了ceil(向上取整)函数。
二、 陶陶摘苹果
题目描述
陶陶家的院子里有一棵苹果树,每到秋天树上就会结出 10 个苹果。苹果成熟的时候,陶陶就会跑去摘苹果。陶陶有个 30 厘米高的板凳,当她不能直接用手摘到苹果的时候,就会踩到板凳上再试试。
现在已知 10 个苹果到地面的高度,以及陶陶把手伸直的时候能够达到的最大高度,请帮陶陶算一下她能够摘到的苹果的数目。假设她碰到苹果,苹果就会掉下来。
输入格式
输入包括两行数据。第一行包含 10 个 100 到 200 之间(包括 100 和 200 )的整数(以厘米为单位)分别表示 10 个苹果到地面的高度,两个相邻的整数之间用一个空格隔开。第二行只包括一个 100 到 120 之间(包含 100 和 120 )的整数(以厘米为单位),表示陶陶把手伸直的时候能够达到的最大高度。
输出格式
输出包括一行,这一行只包含一个整数,表示陶陶能够摘到的苹果的数目。
样例 #1
样例输入 #1
100 200 150 140 129 134 167 198 200 111
110
样例输出 #1
5
我的答案
#include<iostream>
using namespace std;
int main(){
int a[10]={0};
int maxheight,n;
for(int i=0;i<10;i++)
{
cin>>a[i];
}
cin>>maxheight;
for(int i=0;i<10;i++)
{
if(a[i]<=maxheight+30)
{
n++;
}
}
cout<<n;
return 0;
}
三、 校门外的树
题目描述
某校大门外长度为 l 的马路上有一排树,每两棵相邻的树之间的间隔都是 1 米。我们可以把马路看成一个数轴,马路的一端在数轴 0 的位置,另一端在 l 的位置;数轴上的每个整数点,即 0,1,2,\dots,l,都种有一棵树。
由于马路上有一些区域要用来建地铁。这些区域用它们在数轴上的起始点和终止点表示。已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分。现在要把这些区域中的树(包括区域端点处的两棵树)移走。你的任务是计算将这些树都移走后,马路上还有多少棵树。
输入格式
第一行有两个整数,分别表示马路的长度 l 和区域的数目 m。
接下来 m 行,每行两个整数 u, v,表示一个区域的起始点和终止点的坐标。
输出格式
输出一行一个整数,表示将这些树都移走后,马路上剩余的树木数量。
样例 #1
样例输入 #1
500 3
150 300
100 200
470 471
样例输出 #1
298
提示
【数据范围】
- 对于 20% 的数据,保证区域之间没有重合的部分。
- 对于 100% 的数据,保证 。
常见错解(忽略掉可能重合这一点)
#include<iostream>
using namespace std;
int main(){
int l,m;
cin>>l>>m;
int begin[m],end[m];
int a;
for(int i=0;i<m;i++)
{
cin>>begin[i]>>end[i];
a=end[i]-begin[i]+1;
l-=a;
}
l++;//考虑端点
cout<<l;
return 0;
}
正解一(数组,推荐)
#include <iostream>
using namespace std;
int main()
{
int l, m;
cin >> l >> m;
int trees_count[l + 1] = {0}; // 初始化所有位置都没有被标记
while (m--)
{
int start, end;
cin >> start >> end;
for (int i = start; i <= end; ++i)
{
++trees_count[i]; // 标记该区间内的树木被移走了
}
}
int count = 0;
for (int i = 0; i <= l; ++i)
{
if (trees_count[i] == 0)
{
++count; // 统计还剩下多少棵树
}
}
cout << count << endl;
return 0;
}
这里使用了一个数组 trees_count
,用来记录每个位置上树木被标记的次数。在遍历每个区间时,将其中的树木标记为被移走了,也就是在对应的位置上加一。最后在统计剩余的树木数量时,只有当某个位置上被标记的次数为 0 时,才算是还剩下一棵树,因为如果被标记了多次,说明这些树木已经全部移走了。
正解二(bool结合数组)
#include <iostream>
using namespace std;
int main()
{
int l, m;
cin >> l >> m;
bool trees[l + 1] = {true}; // 初始化所有位置都有树
int count[l + 1] = {0}; // 初始化所有位置上树木还没有被标记
while (m--)
{
int start, end;
cin >> start >> end;
for (int i = start; i <= end; ++i)
{
if (trees[i])
{
--count[i]; // 如果该位置上原来有树,先减去一次
}
++count[i]; // 标记该区间内的树木被移走了
}
}
int remaining = 0;
for (int i = 0; i <= l; ++i)
{
if (count[i] == 0)
{
trees[i] = true; // 如果该位置上没有被标记过,说明还有树
++remaining; // 统计还剩下多少棵树
}
}
cout << remaining << endl;
system("pause");
}
解题思想和第一种解法相同。
还有其他解法,比较复杂,这里不再详述。