A 题(幸运数):

答案:4430091

思路:只需要偶数位,那么就只枚举偶数位的数字,不管奇数位的数字,省时间。

但是直接枚举整个数字再分拆成两段显然常数有点大,所以我们可以分别枚举数字的前半段与后半段,分别判断数位和是否相等就会好做很多。

一亿之内的偶数位数字,有 1000 0000 ~ 9999 9999,10 0000 ~ 99 9999,1000 ~ 999,10 ~ 99 这几个范围。因为奇数位的没有被枚举,中间有空档,所以枚举的运算量不超过一亿。分拆数字的那一个 log 因为过小(最大也为 4),可以被丢掉。就算算上最大运算量也大约在一亿,轻松一秒之内跑过。

实际上不分类讨论,直接从 1 蛮到 1 0000 0000 也只需要 10 秒……出题人你在干什么,完全看不懂这道题想考察什么。

代码:

//
//  main.cpp
//  幸运数
//
//  Created by SkyWave Sun on 2023/4/8.
//

#include <iostream>
using namespace std;
int numSum(int num) {
    int ans = 0;
    while (num) {
        ans += num % 10;
        num /= 10;
    }
    return ans;
}
int main(int argc, const char * argv[]) {
    int sum = 0;
    for (int i = 1; i <= 9; ++i) {
        for (int j = 0; j <= 9; ++j) {
            if (numSum(i) == numSum(j)) {
                ++sum;
            }
        }
    }
    for (int i = 10; i <= 99; ++i) {
        for (int j = 00; j <= 99; ++j) {
            if (numSum(i) == numSum(j)) {
                ++sum;
            }
        }
    }
    for (int i = 100; i <= 999; ++i) {
        for (int j = 000; j <= 999; ++j) {
            if (numSum(i) == numSum(j)) {
                ++sum;
            }
        }
    }
    for (int i = 1000; i <= 9999; ++i) {
        for (int j = 0000; j <= 9999; ++j) {
            if (numSum(i) == numSum(j)) {
                ++sum;
            }
        }
    }
    printf("%d\n",sum);
    return 0;
}

B 题(有奖问答):

答案:8335366

思路:背包典题,但是一看范围……怎么才 30,不爆搜都对不起出题人。

爆搜记录两个参数,当前做的是哪道题,当前分数是多少。每次有两种情况,对与不对。对的话就开始做下一道题,分数 + 10,否则也开始做下一道题,分数置 0。如果分数等于 70 的话就增加答案,注意这里不能回溯,因为还有可能达到 70,分数被置 0 后又达到 70了。如果分数达到 100 要根据题意直接回溯,如果题全部答完了也要进行回溯。

时间复杂度为 O(2^n)​​​​​​​ ,最大运算量为十亿,十秒搜出来。

代码:

//
//  main.cpp
//  有奖问答
//
//  Created by SkyWave Sun on 2023/4/8.
//

#include <iostream>
using namespace std;
int ans = 0;
void dfs(int pos, int sum) {
    if (sum == 70) {
        ++ans;
    }
    if (sum == 100) {
        return;
    }
    if (pos == 31) {
        return;
    }
    dfs(pos + 1, sum + 10);
    dfs(pos + 1, 0);
}
int main(int argc, const char * argv[]) {
    dfs(1, 0);
    printf("%d\n",ans);
    return 0;
}

锐评:

首先作为场外选手,评价是题目质量比上一次比赛要好得多。没有像上次出现题面有争议、表述不清的情况,题目也稍有意思些,没有出现放了个题目不知道要考察啥的表现。

但——除了填空题。

这次的填空题是真的垃圾。首先 A 组和 B 组的填空题应该对调一下, B 组两道题目都比 A 组难。A 组居然考两道爆搜,不需要任何优化的那种,完全不知道在考察选手的啥,码力?还是 dfs 又没有学好?反观 B 组的两道题目,第一道题虽然是搜索,但好歹你没加剪枝,比赛结束跑不出来。第二道题同。反观 A 组,第一道题毫不剪枝,蛮力枚举也只需要 10 秒。第二道题更离谱,哪个人教你 dp 题的 n 开 30的???同样 10 秒跑出来。

唯一有一丁点思维含量的还是 B 组的第二道题目,没错,就一丁点。小学二年级奥数的思维。但这道题实在不适合出道填空题里面,因为这个信息熵根据自己的直觉都能知道答案的大致范围……首先信息熵和长度的一半非常相近,那么很多人就想到了从长度的一半往前枚举。然后发现一段时间搜不出来,再把这个枚举的起点往前移。说实话答案就离长度差六十万而已……人品好的肯定有试出来的。

就作为一个出题人,你做填空题你要做一定要用机器判断的。就像第一题一样,100 里挑 8 个数哪个人能在赛时完成?但是你出一个能用人类直觉观察出来的,合适吗?

所以总结:今年 C++ 组填空四道爆搜。蓝桥杯新增称号:爆搜杯。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐