【深入浅出程序设计竞赛(基础篇)第四章 算法从0开始】

第四章 例题

例4-1

#include<iostream>
using namespace std;
int main(){
    int L, i; cin >> L;
    for (i = 1; i <= L; i++) {
        cout << "Today, I ate " << i << " apple";
        if (i != 0 && i != 1) cout << "s";
        cout << "." << endl;
    }
    return 0;
}

例4-2

#include<iostream>
using namespace std;
int main(){
    int n, tmp, minnum = 100000000;
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> tmp;
        if (tmp < minnum) minnum = tmp;
    }
    cout << minnum << endl;
    return 0;
}

例4-3

更简单的解法

#include<cstdio>
using namespace std;
int main(){
    int n, k, i;
    int Asum = 0, Bsum = 0;
    scanf("%d%d", &n, &k);
    if (n < k) {
        Asum = 0;
    }else {
        Asum = (n / k + 1) * (n / k) / 2 * k;
    }
    Bsum = (n + 1) * n / 2 - Asum;
    printf("%.1f %.1f",  double(Asum) / (n / k), double(Bsum) / (n - n / k));
    return 0;
}

书上解法

#include<cstdio>
using namespace std;
int main(){
    int n, k, i;
    int Asum = 0, Bsum = 0;
    scanf("%d%d", &n, &k);
    for (i = k; i <= n; i += k) {
        Asum += i;
    }
    Bsum = (1 + n) * n / 2 - Asum;
 printf("%.1f %.1f",  double(Asum) / (n / k), double(Bsum) / (n - n / k)); //%lf仅用于读入double类型变量而不用于输出
    return 0;
}

例4-4

#include<iostream>
using namespace std;
int main(){
    int a, days = 1;
    cin >> a;
    while(a > 1)
        days++, a /= 2;
    cout << days;
    return 0;
}

例4-5

#include<iostream>
#include<cstdlib>
#include<ctime>
using namespace std;
int main(){
    int ans, guess;
    srand(time(0));
    ans = rand() % 100 + 1;
    cout << ans;
    do {
        cin >> guess;
        if (guess < ans) 
            cout << "Too small" << endl;
        if (guess > ans)
            cout << "Too large" << endl;
    }while(ans != guess);
    cout << "You are right!!!" << endl;
    return 0;
}

例4-6

#include<cstdio>
using namespace std;
int main(){
    int cnt = 0, n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n - i + 1; j++) {
            printf("%02d", ++cnt);
        }
        printf("\n");
    }
    return 0;
}

例4-7

这道题书上的题解并不能解答洛谷P1009的题目,等后面学到第八章再来更新答案

#include<iostream>
using namespace std;
int main(){
    long long n, ans = 0;
    cin >> n;
    for(int i = 1; i <= n; i++){
        long long factor = 1;
        for(int j = 1; j <= i; j++){
            factor *= j;
        }
        ans += factor;
    }
    cout << ans << endl;
}

也可以采用递归

#include<iostream>
using namespace std;

long long calc(int n){
    if(n == 1)
        return 1;
    else
        return calc(n-1) * n;
}

int main(){
    long long n, ans = 1;
    cin >> n;
    for(int i = 2; i <= n; i++){
        ans += calc(i);
    }
    cout << ans << endl;
}

例4-8

#include<iostream>
using namespace std;

int main(){
    int n, x, ans = 0;
    cin >> n >> x;
    for(int i = 1; i <= n; i++){
        int tmp = i, num;
        while(tmp != 0){
            num = tmp % 10;
            if(num == x)
                ans++;
            tmp /= 10;
        }
    }
    cout << ans;
    return 0;
}

例4-9

#include<iostream>
using namespace std;

int main(){
    int k, ans = 0;
    cin >> k;
    for(double Sn = 0; Sn <= k; ans++, Sn += 1.0 / ans);
    cout << ans;
    return 0;
}

例4-10

书上解法

#include<iostream>
using namespace std;

int main(){
    int k, coin = 0, day = 0;
    cin >> k;
    for(int i = 1;; i++){
        for(int j = 1; j <= i; j++){
            coin += i; day++;
            if(day == k){
                cout << coin << endl;
                return 0;
            }
        }
    }
    return 0;
}

我的解法

#include<iostream>
using namespace std;

int main(){
    int k, ans = 0, i;
    cin >> k;
    for(i = 1; i <=k; i++){
        ans += i * i; //加上当前天数的金币
        k -= i; //保证剩下还有天数
    }
    ans += i * k; //加上剩下天数的钱币
    cout << ans;
    return 0;
}

例4-11

解法一

#include<iostream>
using namespace std;

int main(){
    int n, s = 0;
    cin >> n;
    for(int i = 1; i <= n; i++){
        s += i;
    };
    cout << s;
    return 0;
}

解法二

#include<iostream>
using namespace std;

int main(){
    int s = 0, i = 0, n;
    cin >> n;
    while(n--) s += ++i;
    cout << s;
    return 0;
}

例4-12

#include<iostream>
using namespace std;

int main(){
    double n, s = 0;
    cin >> n;
    for(int i = 1; i <= n; i++){
        s += i * 0.1;
    };
    cout << s;
    return 0;
}

错误代码,注意精度

#include<iostream>
using namespace std;

int main(){
    int n;
    double s = 0;
    cin >> n;
    for(double i = 0.1; i != n; i += 0.1){
        s += i; 
        // cout << s << endl;
    }
    cout << s;
    return 0;
}

例4-13

#include<iostream>
using namespace std;

int main(){
    int L, load = 0, ans = 0;
    cin >> L;
    for(int i = 2; ; i++){
        int is_prime = 1;
        // for(int j = 2; j * j <= i; j++){ //正常写应该是j <= sqrt(i),改为乘法加快运算速度
            if(i % j == 0){
                is_prime = 0;
                break;
            }
        }
        if(!is_prime) continue;
        if(i + load > L) break;
        cout << i << endl;
        ans++; load += i;
    }
    cout << ans;
    return 0;
}

例4-14

解题思路:
1、因为回文数的数量很少,所以先构造回文数
题目数据范围:5≤a<b≤100,000,000

  • 数据位数可以是1、2、3、4、5、6、7、8、9
  • 位数为1且>=5的回文数质数:5、7
  • 位数为2的回文数质数:11
  • 位数为4、6、8的回文数都是11的整数倍不是质数,不予考虑
  • 位数为3、5、7的回文数:自己构造
  • 位数为9的数只有一个100000000显然不满足条件,不予考虑

2、再判断是否是质数
3、如果符合条件则输出

#include<iostream>
using namespace std;

int is_prime(int x){
    if(x % 2 == 0) return 0; //偶数一定不是质数
    for(int i = 3; i * i <= x; i++){
        if(x % i == 0) return 0;
    }
    return 1;
}

int main(){
    int a, b;
    cin >> a >> b;
    //回文数奇数位为1时 只有 2 3 5 7满足是质数,本题范围>=5,所以只有5 7
    if(a <= 5 && b >= 5) cout << 5 << endl;
    if(a <= 7 && b >= 7) cout << 7 << endl;
    // 回文数位数为偶数时,只有11为质数,其他都是11的倍数,如1001、1221、345543
    if(a <= 11 && b >= 11) cout << 11 << endl;

    //3、5、7枚举
    //三位数的回文数
    for(int d1 = 1; d1 <= 9; d1 += 2){ //开头数字不能为0,偶数一定不是质数
        for(int d2 = 0; d2 <= 9; d2++){
            int num = 100 * d1 + 10  * d2 + d1;
            if(num < a) continue;
            if(num > b) return 0;
            if(is_prime(num)) cout << num << endl;
        }
    }

    //五位数的回文数
    for(int d1 = 1; d1 <= 9; d1 += 2){
        for(int d2 = 0; d2 <= 9; d2++){
            for(int d3 = 0; d3 <= 9; d3++){
                int num = 10000 * d1 + 1000*d2 + 100 * d3 + 10 * d2 + d1;
                if(num < a) continue;
                if(num > b) return 0;
                if(is_prime(num)) cout << num << endl;
            }
        }
    }

     //七位数的回文数
    for(int d1 = 1; d1 <= 9; d1 += 2){
        for(int d2 = 0; d2 <= 9; d2++){
            for(int d3 = 0; d3 <= 9; d3++){
                for(int d4 = 0; d4 <= 9; d4++){
                    int num = 1000000 * d1 + 100000*d2 + 10000 * d3 + 1000 * d4 + 100 * d3 + 10 * d2 + d1;
                    if(num < a) continue;
                    if(num > b) return 0;
                    if(is_prime(num)) cout << num << endl;
                }
            }
        }
    }

    return 0;
}

第四章 课后习题

4-1

使用c++自带的库函数

#include<iostream>
#include<algorithm>
using namespace std;
int main(){
    int a[5] = {11, 3, 5, 90, 20};
    sort(a, a+5);
    cout << a[4];
    return 0;
}

自己写排序算法,如冒泡排序
做了两处优化:1、循环次数优化 2、flag标志减少排序次数

#include<iostream>
using namespace std;
int main(){
    int a[5] = {11, 3, 5, 90, 20}, temp, flag;
    for(int i = 0; i < 5 - 1; i++){
        for(int j = 0; j < 5 - 1 - i; j++){
            flag = 0;
            if(a[j] > a[j + 1]){
                temp = a[j];
                a[j] = a[j + 1];
                a[j + 1] = temp;
                flag = 1;
            }
        }
        if(!flag) break; //如果flag没有改变,则说明数据已经排好序,无需继续排序
    }
    for(int i = 0; i < 5; i++) cout << a[i] << endl;
    return 0;
}

4-2

等比数列求和公式s = a1 * (1 - q ^ n) / (1 - q)
反推n = log(1 - (1 - q) / 2 * s) / log(q)
题目中n全部都是整数,也就是说,宁可多走一步步,让实际路程>=要求路程
因此在上式中,一旦n算出来是带小数的,就得把它进一位,因此再加一个ceil函数
a1 = 2, q = 0.98,即n = ceil(log(1 - 0.01 * s) / log(0.98))

#include<iostream>
#include<cmath>
using namespace std;
int main(){
    float s, sum = 2;
    cin >> s;
    int ans;
    ans = ceil(log(1 - 0.01 * s) / log(0.98));
    cout << ans;
    return 0;
}

4-3

巧妙之处在于可以用字符串接收数字会很方便反转,对对应位直接进行加减也就没有了前置0 问题了

#include<iostream>
#include<cmath>
using namespace std;

int main(){
    string a;
    cin >> a;
    long long ans = 0;
    if(a[0] == '-'){
        for(int i = a.length() - 1; i >= 1; i--){
            ans -= (a[i] - '0') * pow(10, i-1);
        }
    }else{
        for(int i = a.length() - 1; i >= 0; i--){
           ans += (a[i] - '0') * pow(10, i);
        }
    }
    cout << ans;
    return 0;
}

4-4

斐波那契数列

解法一:递归
但是洛谷超时

#include<cstdio>
using namespace std;

float cum(int n){
    if(n == 0){
        return 0;
    }else if(n == 1 || n == 2){
        return 1;
    }
    else{
        return cum(n-1) + cum(n-2);
    }
}

int main(){
    int n;
    scanf("%d", &n);
    float ans = cum(n);
    printf("%.2f", ans);
    return 0;
}

解法二:
递推

#include<cstdio>
using namespace std;

int main(){
    int n;
    scanf("%d", &n);
    double f[50] = {0, 1, 1};
    for(int i = 3; i <= n; i++){
        f[i] = f[i - 1] + f[i - 2];
    }
    printf("%.2lf", f[n]);
    return 0;
}

4-5

#include<iostream>
using namespace std;

int main(){
    int n;
    cin >> n;
    int temp, min = 1001, max = -1;
    for(int i = 0; i < n; i++){
        cin >> temp;
        if(temp < min) min = temp;
        if(temp > max) max = temp;
    }
    cout << max - min;
    return 0;
}

4-6

#include<iostream>
using namespace std;

int main(){
    int n;
    cin >> n;
    int f[n];
    for(int i = 0; i < n; i++){
        cin >> f[i];
    }
    int c = 1, ans = 1;
    for(int i = 0; i < n - 1; i++){
        if(f[i + 1] - f[i] == 1) c++;
        else c = 1;
        if(c > ans) ans = c;
    }
    cout << ans;
    return 0;
}

4-7

唯一分解定理: 一个数能且只能分解为一组质数的乘积。
可知,若输入的数满足题目条件,他就只能分解为两个质数的乘积。所以在比他小且大于1的自然数中,只有那两个数能整除它,之间不可能再有任何合数或质数能整除它了,因为最小的能整除它的合数已经是他本身了。

#include<iostream>
using namespace std;

int main(){
    int n;
    cin >> n;
    for(int i = 2; i < n; i ++){
        if(n % i == 0){
            cout << n / i;
            break;
        }
    }
    return 0;
}

4-8

#include<cstdio>

int main(){
    int n;
    scanf("%d", &n);

    int c = 1;
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            printf("%02d", c);
            c++;
        }
        printf("\n");
    }

    printf("\n");

    c = 1;
     for(int i = 1; i <= n; i++){
        for(int k = 1; k <= 2 * n - 2 * i; k++){
            printf(" " );
        }
        for(int j = 1; j <= i; j++){
            printf("%02d", c);
            c++;
        }
        printf("\n");
    }
    return 0;
}

4-9

#include<bits/stdc++.h>
using namespace std;

int main(){
    int n;
    cin >> n;
    int a[n];
    for(int i = 0; i < n; i++){
       cin >> a[i];
    }
    sort(a, a+n);
    double ans;
    for(int i = 1; i < n - 1; i++){
        ans += a[i];
    }
    printf("%.2lf", ans / (n - 2));
    return 0;
}

4-10

#include<bits/stdc++.h>
using namespace std;

int main(){
    int n;
    cin >> n;
    int start = n / 364;
    if(start > 100) start = 100;
    for(int i = start; i >= 1; i--){
        int k = 1;
        while(k > 0){
            if((i + 3 * k) * 364 == n){
                cout << i << endl;
                cout << k << endl;
                return 0;
            }
            else if((i + 3 * k) * 364 > n){
                break;
            }
            k++;
        }
    }
    return 0;
}

4-11

#include<bits/stdc++.h>
using namespace std;

int main(){
    int cost = 0, balance = 0, money = 0;
    for(int i = 1; i <= 12; i++){
        cin >> cost;    
        balance += 300 - cost;
        if(balance < 0){
            cout << -i;
            return 0;
        }
        else if(balance % 100 >= 0){
            money +=  balance - balance % 100;
            balance = balance % 100;
        }
    }
    cout << money * 1.2 + balance;
    return 0;
}
### 回答1: 《洛谷深入浅出程序设计竞赛(基础) pdf》是一本关于程序设计竞赛基础知识的书籍,主要面向初学者。本书作者通过深入浅出的方式,以简洁清晰的语言讲解了程序设计竞赛中常见的基础知识和技巧。 该书首先介绍了算法数据结构的基本概念,包括常见的排序算法、栈、队列、链表、树等数据结构。然后,详细讲解了常用的算法设计技巧,如贪心算法、动态规划、递归等,并通过大量的例题进行了实践演练,使读者能更好地理解和掌握这些技巧。 此外,本书还介绍了常见的编程语言和开发环境,如C++、Python和Java等,并提供了一些常用的程序调试技巧和工具,帮助读者解决实际编程过程中可能遇到的问题。 《洛谷深入浅出程序设计竞赛(基础) pdf》还包含了大量的习题和实例,供读者进行练习和巩固所学知识。同时,书中还提供了一些实战经验和竞赛技巧,帮助读者提高在程序设计竞赛中的表现。 总的来说,《洛谷深入浅出程序设计竞赛(基础) pdf》适合初学者入门,内容全面、易懂,对于想要了解程序设计竞赛基础知识和提升编程能力的人来说是一本很好的参考书。 ### 回答2: 《洛谷深入浅出程序设计竞赛(基础) pdf》是一本内容丰富、有助于初学者提高编程能力的书籍。该书主要介绍了洛谷这个在线判题系统的使用方法以及一些常见的算法数据结构知识。 首先,书中详细介绍了洛谷这个在线判题系统的功能和使用方法。洛谷是一个非常受欢迎的在线编程平台,它提供了丰富的题目和在线编译环境,使得用户可以更加方便地练习和学习编程。书中通过简单明了的语言和图文并茂的示例,向读者介绍了洛谷的登录、题目搜索、代码提交等基本操作,帮助读者迅速上手这个平台。 其次,书中系统地介绍了一些常见的算法数据结构知识。这对于初学者来说,是非常重要的一部分。书中通过具体的例子和详细的讲解,向读者介绍了一些常见的算法,如搜索、排序和动态规划等。同时,书中还提供了一些实操编程题目,使得读者可以通过练习加深对这些算法的理解和掌握。 总的来说,《洛谷深入浅出程序设计竞赛(基础) pdf》是一本对于初学者来说非常有价值的书籍。它通过详细的介绍洛谷系统的使用方法和常见算法的讲解,帮助读者快速入门,并且提高编程能力。阅读这本书,不仅可以帮助初学者更好地了解和使用洛谷系统,还可以提供一些常见算法的思路和实践经验,对于参加编程竞赛和提升编程能力有着积极的影响。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小白*进阶ing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值