CSDN 编程竞赛第十期题解

竞赛总览

CSDN编程竞赛第十期:比赛详情 (csdn.net)

本次竞赛共四道题,其中前两题难度较低。

竞赛题解

题目1、熊孩子拜访

已知存在一个长度为n的整数序列A。 A中所有元素按照从小到大的顺序进行排序。现在执行操作倒置一段序列。 请找到A序列里的倒置子序列。

根据题目描述可知,整数序列整体为升序,且其中只有一段倒置子序列。
使用两个索引指针来记录倒置子序列的起始位置。
两个索引指针默认都指向序列中的第一个值。
从第二个值开始,遍历整个序列。
如果当前位置的值比前一个位置的值更大或相等(且两个指针指向的位置相同),说明当前序列位置保持升序状态,更新索引,起始位置和终止位置都更新为当前位置索引。
否则,判断当前位置的值是否比终止位置指针指向的值更小,如果满足条件说明该段子序列为降序状态,此时需要更新终止位置。
否则,跳出循环。
此时即可得到倒置子序列的起始位置和终止位置。
根据题目要求,如果两个索引指针指向的位置相同,输出0 0。
否则,输出对应位置的值即可。

题目2、走楼梯

现在有一截楼梯,根据你的腿长,你一次能走1级或2级楼梯,已知你要走n级楼梯才能走到你的目的楼层,请实现一个方法,计算你走到目的楼层的方案数。

经典的递归问题。一次可以上1阶或2阶楼梯。
从最基础的情况开始考虑:
如果楼层为1,只有1种方案,方案数为 f (1) = 1。
如果楼层为2,有2种方案,1+1、2,方案数为 f (2) = 2。
如果楼层为3,此时可以在楼层为1的基础上再上2阶楼梯,也可以在楼层为2的基础上再上1阶楼梯,此时方案数为:f (3) = f (2) + f (1)。
得到递推公式,f (n) = f (n - 1) + f (n - 2)。
直接使用递归会进行很多无谓的计算,可以写个循环先把所有值都算出来,然后要什么就返回什么即可。
这道题给的C++模板有些问题,模板用的是int类型,答案范围是long long int类型。如果直接使用模板,无法得到全部分数。

递归问题的核心思想是通过基础状态得到复杂状态,通常,比较简单的状态可以在程序中直接返回,复杂的状态可以使用递推公式得到。

例如,走楼梯问题的递归函数为:

int f (int n) {
    if (n <= 1) return 1;
    if (n == 1) return 1;
    if (n == 2) return 2;
    return f (n - 1) + f (n - 2);
}

题目3、括号上色

小艺酱又得到了一堆括号。 括号是严格匹配的。 现在给括号进行上色。 上色有三个要求: 1、只有三种上色方案,不上色,上红色,上蓝色。 2、每对括号只有一个上色。 3、相邻的两个括号不能上相同的颜色,但是可以都不上色。 问括号 上色有多少种方案?答案对1000000007取模。

动态规划问题,相当于递归的升级版,通过开辟一个内存数组来存储中间状态,后面的状态可以通过基础状态求得。

注意到测试数据有一组(()),还有一个(),如果已经算出(())的涂色方案,那么(())()的方案可以在(())的基础上,加上()的方案求得。

这个题目中还有一些边界限制,不能直接使用子序列的方案数。例如(())的右边界(右括号)已经染色,根据题意(())()右边的()的左括号不能与(())的右括号染成相同颜色。

这道题目的思路是:

用栈对括号对进行分析,用一个一维数组记录配对括号的位置。给出左括号,能够找到与其配对的右括号的位置,反之亦然。

建立一个四维的数组,存储a到b区间上左右边界染色的情况,数组的形状为dp[len][len][3][3]。根据染色情况进行状态转移。

题目4、喜水青蛙

总是喜欢在水里嬉戏的青蛙,某天要过河拜访一位朋友。 已知河道中长满了带刺的不知名生物,能通过的路只有一条直线,长度为L。 直线上随机分布着m块石头。青蛙的最小跳跃距离是s,最大跳跃距离是t。 青蛙想要尽可能的少踩石头,那么它通过河道最少会踩到多少石头?

这道题是十几年前的一道NOIP试题,属于中等难度。需要注意的是,青蛙过河可以不踩石头。

河的长度L是int范围,而石头的数量却很少,如果暴力枚举的话会超时,因此这道题需要进行状态压缩。首先,由于并不确定输入数据给定的石头位置是否是从小到大的,所以需要对石头的位置进行排序。接下来,如果两块石头之间的距离过大,可以将它们的距离进行压缩。

感兴趣的话可以去看一下NOIP试题集,上面有历年NOIP题目的详细分析过程。如果实在做不出来也可以输出一个概率比较大的值,例如0、1、2等,可以骗到一些分。

你可能感兴趣的:(CSDN,竞赛题解,算法,c++)