第十一届蓝桥杯大赛软件类决赛(C/C++ 大学A组)

本文详细解析了蓝桥杯竞赛中的五个题目,包括计算合数个数的算法、皮亚诺曲线的长度计算、玩具蛇的放置策略、出租车行程最优化以及机器人蓝跳跳的行走方案多样性。通过解决这些问题,深入理解了分形、动态规划和路径优化等技术应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


  蓝桥杯个人赛软件类历届真题及其解析


试题 A: 合数个数

本题总分: 5 5 5


【问题描述】

  一个数如果除了 1 1 1 和自己还有其他约数,则称为一个合数。例如: 1 , 2 , 3 1, 2, 3 1,2,3 不是合数, 4 , 6 4, 6 4,6 是合数。

  请问从 1 1 1 2020 2020 2020 一共有多少个合数。

【答案提交】

  这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。


1713


#include <stdio.h>

const int N = 2020;

int ans, factor[N + 1];

int main() {
   
    for (int i = 2; i <= N; ++i)
        if (factor[i]) ++ans;
        else
            for (int j = i; j <= N; j += i)
                factor[j] = 1;
    printf("%d", ans);
}

  这码风,程序设计老师看了直摇头。


试题 B: 含 2 天数

本题总分: 5 5 5


【问题描述】

  小蓝特别喜欢 2 2 2,今年是公元 2020 2020 2020 年,他特别高兴,因为每天日历上都可以看到 2。

  如果日历中只显示年月日,请问从公元 1900 1900 1900 1 1 1 1 1 1 日到公元 9999 9999 9999 12 12 12 31 31 31 日,一共有多少天日历上包含 2 2 2。即有多少天中年月日的数位中包含数字 2 2 2


【答案提交】

  这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。


1994240


#include <stdio.h>

int ans, days[]{
   0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

int isLeap(int year) {
    return !(year % 100 ? year % 4 : year % 400); }

int contain2(int num) {
    do if (num % 10 == 2) return 1; while (num /= 10); }

int main() {
   
    for (int year = 1900; year <= 9999; ++year) {
   
        if (isLeap(year)) days[2] = 29;
        for (int month = 1; month <= 12; ++month)
            for (int day = 1; day <= days[month]; ++day)
                if (contain2(year) || contain2(month) || contain2(day)) ++ ans;
        days[2] = 28;
    }
    printf("%d", ans);
}

  摇头。


试题 C: 本质上升序列

本题总分: 10 10 10


【问题描述】

  小蓝特别喜欢单调递增的事物。

  在一个字符串中,如果取出若干个字符,将这些字符按照在字符串中的顺序排列后是单调递增的,则成为这个字符串中的一个单调递增子序列。

  例如,在字符串 l a n q i a o \mathrm{lanqiao} lanqiao 中,如果取出字符 n \mathrm{n} n q \mathrm{q} q,则 n q \mathrm{nq} nq 组成一个单调递增子序列。类似的单调递增子序列还有 l n q \mathrm{lnq} lnq i \mathrm{i} i a n o \mathrm{ano} ano 等等。

  小蓝发现,有些子序列虽然位置不同,但是字符序列是一样的,例如取第二个字符和最后一个字符可以取到 a o \mathrm{ao} ao,取最后两个字符也可以取到 a o \mathrm{ao} ao
  小蓝认为他们并没有本质不同。

  对于一个字符串,小蓝想知道,本质不同的递增子序列有多少个?

  例如,对于字符串 l a n q i a o \mathrm{lanqiao} lanqiao,本质不同的递增子序列有 21 21 21 个。它们分别是 l \mathrm{l} l a \mathrm{a} a n \mathrm{n} n q \mathrm{q} q i \mathrm{i} i o \mathrm{o} o l n \mathrm{ln} ln a n \mathrm{an} an l q \mathrm{lq} lq a q \mathrm{aq} aq n q \mathrm{nq} nq a i \mathrm{ai} ai l o \mathrm{lo} lo a o \mathrm{ao} ao n o \mathrm{no} no i o \mathrm{io} io l n q \mathrm{lnq} lnq a n q \mathrm{anq} anq l n o \mathrm{lno} lno a n o \mathrm{ano} ano a i o \mathrm{aio} aio

  请问对于以下字符串(共 200 200 200 个小写英文字母,分四行显示):(如果你把以下文字复制到文本文件中,请务必检查复制的内容是否与文档中的一致。在试题目录下有一个文件 inc.txt,内容与下面的文本相同)

tocyjkdzcieoiodfpbgcncsrjbhmugdnojjddhllnofawllbhf
iadgdcdjstemphmnjihecoapdjjrprrqnhgccevdarufmliqij
gihhfgdcmxvicfauachlifhafpdccfseflcdgjncadfclvfmad
vrnaaahahndsikzssoywakgnfjjaihtniptwoulxbaeqkqhfwl

  本质不同的递增子序列有多少个?


【答案提交】

  这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。


3616159


动态规划


  首先考虑上升子序列问题,即子串可以相同的情况。

  设 f i f_i fi 为以字符串 S [ 1 , n ] S[1,n] S[1,n] i i i 个字符结尾的最长递增子序列的个数,则总个数为 ∑ i = 1 n f i \sum_{i=1}^nf_i i=1nfi,状态转移方程为 f i = ∑ j = 1 i − 1 f j ( S [ i ] > S [ j ] ) f_i = \sum_{j=1}^{i-1}f_j(S[i] > S[j]) fi=j=1i1fj(S[i]>S[j])

  为了避免出现重复子串,考虑互斥的划分方式,

  有状态 f i , c f_{i,c} fi,c 表示到第 i i i 个字符为止,以 c c c 结尾的本质不同子串的个数为多少,显然答案为 ∑ c f n , c \sum_c f_{n,c} cfn,c

  可是如何保证不重不漏呢?

  对于 c ≠ S [ i ] c \neq S[i] c=S[i],显然有 f i , c = f i − 1 , c f_{i,c} = f_{i - 1, c} fi,c=fi1,c,而对于 c = S [ i ] c = S[i] c=S[i] 的情况,考虑重新统计即 f i , c = ∑ c ′ = 1 c − 1 f i − 1 , c ′ f_{i,c} = \sum_{c'=1}^{c-1}f_{i-1,c'} fi,c=c=1c1fi1,c,不重是做到了,即可不重不漏。

   证明半天证明了一坨屎,其实可以用反证法,但反证太无聊了。

#include <iostream>

std::string s = "$", buf;

int dp[0xff], ans;

int main() {
   
    freopen("inc.txt", "r", stdin);
    while (std::cin >> buf) s += buf;
    for (int i = 1; i <= 200; ++i) {
   
        ans -= dp[s[i]], dp[s[i]] = 1;
        for (int j = s[i] - 1; j >= 'a'; --j) dp[s[i]] += dp[j];
        ans += dp[s[i]];
    }
    printf("%d", ans);
}

试题 D: 咫尺天涯

本题总分: 10 10 10


【问题描述】

  皮亚诺曲线是一条平面内的曲线。

  下图给出了皮亚诺曲线的 1 1 1 阶情形,它是从左下角出发,经过一个 3 × 3 3 × 3 3×3 的方格中的每一个格子,最终到达右上角的一条曲线。
请添加图片描述
  设每个格子的边长为 1 1 1,在上图中,有的相邻的方格(四相邻)在皮亚诺曲线中也是相邻的,在皮亚诺曲线上的距离是 1 1 1,有的相邻的方格在皮亚诺曲线中不相邻,距离大于 1 1 1

  例如,正中间方格的上下两格都与它在皮亚诺曲线上相邻,距离为 1 1 1,左右两格都与它在皮亚诺曲线上不相邻,距离为 3 3 3

  下图给出了皮亚诺曲线的 2 2 2 阶情形,它是经过一个 3 2 × 3 2 3^2 × 3^2 32×32 的方格中的每一个格子的一条曲线。它是将 1 1 1 阶曲线的每个方格由 1 1 1 阶曲线替换而成。
请添加图片描述
  下图给出了皮亚诺曲线的 3 3 3 阶情形,它是经过一个 3 3 × 3 3 3^3 × 3^3 33×33 的方格中的每一个格子的一条曲线。它是将 2 2 2 阶曲线的每个方格由 1 1 1 阶曲线替换而成。
请添加图片描述
  皮亚诺曲线总是从左下角开始出发,最终到达右上角。

  小蓝对于相邻的方格在皮亚诺曲线上的相邻关系很好奇,他想知道相邻的方格在曲线上的距离之和是多少。

  例如,对于 1 1 1 阶皮亚诺曲线,距离和是 24 24 24,有 8 8 8 对相邻的方格距离为 1 1 1 2 2 2 对相邻的方格距离为 3 3 3 2 2 2 对相邻的方格距离为 5 5 5

  再如,对于 2 2 2 阶皮亚诺曲线,距离和是 816 816 816

  请求出对于 12 12 12 阶皮亚诺曲线,距离和是多少。

  提示:答案不超过 1 0 18 10^{18} 1018


【答案提交】

  这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。


184731576397539360


动态规划


  首先考虑分形问题,但是 3 12 × 3 12 3^{12} × 3^{12} 312×312 的曲线中,相邻的格子对有 2 × 3 12 × ( 3 12 − 1 ) 2 × 3^{12} × (3^{12} - 1) 2×312×(3121) 个,复杂度爆炸。

  于是考虑动态规划,为此需要选择一些合适的属性来表述状态,合适的策略来完成转移。

  容易想到按阶划分,即将一个 k k k 阶的皮亚诺曲线划分为 3 3 3^3 33 k − 1 k - 1 k1 的皮亚诺曲线,而 k − 1 k - 1 k1 阶曲线内部相邻块的距离不受其余同阶曲线的影响,固有状态 f i f_i fi 表示 i i i 阶皮亚诺曲线的距离合, f i = 3 3 f i − 1 + I i f_i = 3^3f_{i-1} + I_i fi=33fi1+Ii I i I_i Ii 表示 k − 1 k - 1

评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值