基础篇(1)

65 阅读3分钟

一、 级数求和

题目描述

已知:Sn=1+12+13++1nS_n= 1+\frac{1}{2}+\frac{1}{3}+…+\frac{1}{n}。显然对于任意一个整数 k,当 n 足够大的时候,Sn>kS_n>k

现给出一个整数 k,要求计算出一个最小的 n,使得 Sn>kS_n>k

输入格式

一个正整数 k。

输出格式

一个正整数 n。

样例 #1

样例输入 #1

1

样例输出 #1

2

提示

【数据范围】

对于 100% 的数据,1k151\le k \le 15

我的答案

#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% 的数据,保证 1l1041m1000uvl1 \leq l \leq 10^4,1 \leq m \leq 100,0 \leq u \leq v \leq l

常见错解(忽略掉可能重合这一点)

#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");
}

解题思想和第一种解法相同。

还有其他解法,比较复杂,这里不再详述。