欢迎光临散文网 会员登陆 & 注册

蓝桥杯赛前补题(一): 2022年C/C++省赛真题个人题解

2023-03-26 15:33 作者:StepfenShawn  | 我要投稿

A: 排列字母(签到题)

小蓝要把一个字符串中的字母按其在字母表中的顺序排列。

例如,LANQIAO 排列后为 AAILNOQ。

又如,GOODGOODSTUDYDAYDAYUP 排列后为 AADDDDDGGOOOOPSTUUYYY

请问对于以下字符串,排列之后字符串是什么?

WHERETHEREISAWILLTHEREISAWAY

根据ANCII值直接排序即可, 时间复杂度:(nlgn)

B: 特殊时间 (枚举)

2022 年 2 月 22 日 22:20 是一个很有意义的时间,年份为 2022,由 3 个 2 和 1 个 0 组成,如果将月和日写成 4 位,为 0222,也是由 3 个 2 和 1 个 0 组

成,如果将时间中的时和分写成 4 位,还是由 3 个 2 和 1 个 0 组成。

小蓝对这样的时间很感兴趣,他还找到了其它类似的例子,比如 111 年 10

月 11 日 01:11,2202 年 2 月 22 日 22:02 等等。

请问,总共有多少个时间是这种年份写成 4 位、月日写成 4 位、时间写成

4 位后由 3 个一种数字和 1 个另一种数字组成。注意 1111 年 11 月 11 日 11:11

不算,因为它里面没有两种数字。

由于年份没有限制, 我们只要判断枚举出来的月份和时间是否合法就行了, 然后利用乘法原理就可以计算出有多少个特殊时间了!

另外有一个更奇妙的方法: 我们可以推出实际上满足的月份日期只有16种, 再每个日期月份排列看看时间合法的数量, 再根据乘法原理相乘就会得出答案:

C.纸张尺寸 (模拟)

在 ISO 国际标准中定义了 A0 纸张的大小为 1189mm × 841mm,将 A0 纸沿长边对折后为 A1 纸,大小为 841mm × 594mm,在对折的过程中长度直接取下整(实际裁剪时可能有损耗)。将 A1 纸沿长边对折后为 A2 纸,依此类推。 

输入纸张的名称,请输出纸张的大小。 

样例输入

A0

样例输出

1189 841

直接模拟, 时间复杂度 O(n):

D.求和 (前缀和)

给定 n 个整数 a1, a2, · · · , an ,求它们两两相乘再相加的和,即 S = a1 · a2 + a1 · a3 + · · · + a1 · an + a2 · a3 + · · · + an-2 · an-1 + an-2 · an + an-1 · an.

对于 30% 的数据,1 ≤ n ≤ 1000,1 ≤ ai ≤ 100。

对于所有评测用例,1 ≤ n ≤ 200000,1 ≤ ai ≤ 1000。

注意到 n 的范围会达到 200000 (10^5数量级), 如果我们直接用两个 for 循环枚举的话时间复杂度会达到 O(n^2) 超出时间限制. 我们观察到S 实际上等于

a1 * (a2 + a3 + ... + an) + a2 * (a3 + a4 + ... + an) + ... + an-1(an)

假如我们计算出数组的前缀和pre, 于是答案就为 %5Csum%5Cnolimits_%7B1%7D%5Ek%20a%5Bi%5D%20*%20pre%5B%5Bi%2C%20n%5D%5D%20,于是我们就可以只用一个 for 循环将时间复杂度优化到 O(n) 级别了(求和可能会溢出,C++要开long long):

E.数位排序 (模拟 + 排序)

小蓝对一个数的数位之和很感兴趣,今天他要按照数位之和给数排序。当两个数各个数位之和不同时,将数位和较小的排在前面,当数位之和相等时,将数值小的排在前面。

例如,2022 排在 409 前面,因为 2022 的数位之和是 6,小于 409 的数位之和 13。

又如,6 排在 2022 前面,因为它们的数位之和相同,而 6 小于 2022。

给定正整数 n,m,请问对 1 到 n 采用这种方法排序时,排在第 m 个的元素是多少? 

对于 30% 的评测用例,1 ≤ m ≤ n ≤ 300。

对于 50% 的评测用例,1 ≤ m ≤ n ≤ 1000。

对于所有评测用例,1 ≤ m ≤ n ≤ 106。 

我们发现直接模拟是可行的, 因为 n 的数量级才 10 ^ 6, 我们枚举每一个数并求出它的数位和进行排序, 时间复杂度为 O(nlgn):

注意题目中的 "当数位之和相等时,将数值小的排在前面", 看漏眼不小心 WA 了一发。。。

 

F: 选数异或(数学 + 动态规划)

给定一个长度为 n 的数列 A1, A2, · · · , An 和一个非负整数 x,给定 m 次查

询, 每次询问能否从某个区间 [l,r] 中选择两个数使得他们的异或等于 x 。

输入的第一行包含三个整数 n, m, x 。

第二行包含 n 个整数 A1, A2, · · · , An 。

接下来 m 行,每行包含两个整数 li,ri 表示询问区间 [li,ri] 。

对于每个询问, 如果该区间内存在两个数的异或为 x 则输出 yes, 否则输出

no。

4 4 1

1 2 3 4

1 4

1 2

2 3

3 3

【样例输出】

yes

no

yes

no

对于 20% 的评测用例,n, m ≤ 500, 1 ≤ a1, a2, · · · , an ≤ 1000;

对于 40% 的评测用例,n, m ≤ 5000;

对于所有评测用例,1 ≤ n, m ≤ 100000, 1 ≤ a1, a2, · · · , an ≤ 100000, 1 ≤ li ≤ ri ≤ n, 1 ≤ ki ≤ n。

由于题目中的n, m数量级很高, 直接暴力会很容易超时, 假设我们在一次查询中在区间[li, ri]找到了两个数使得异或为 x, 那么对任意包含于[li, ri]的区间, 我们的答案都为yes.

我们的目标是找到两个数 a, b使得 a ^ b = x, 对于 a, b 我们唯一知道的是它在[li, ri]中, 但是只知道这一点是不够的, 我们继续来看看a,b和x 满足什么性质:

a ^ b = x

a ^ b ^ a = x ^ a

b ^ 0 = x ^ a

b = x ^ a

于是我们发现 a, b 在区间[li, ri]中,并且 b = x ^ a 也会在 区间 [li, ri]中, 于是我们可以使用map来记录 a 和 b 的位置.

于是我们定义一个 dp[i]: 在[0, i]区间中最大a的位置,并且我们确保了a,b中的a一定是前面那个元素(因为是正向 for 循环), 于是查询的时候我们只需要判断dp[r] 是否大于等于 l 就知道这个区间是否合法了。

G: 消除游戏(暴力)

在一个字符串 S 中,如果 S i = S ii 1 且 S i , S i+1 ,则称 S i 和 S i+1 为边缘

字符。如果 S i , S ii 1 且 S i = S i+1,则 S ii 1 和 S i 也称为边缘字符。其它的字符

都不是边缘字符。

对于一个给定的串 S,一次操作可以一次性删除该串中的所有边缘字符

(操作后可能产生新的边缘字符)。

请问经过 2

64 次操作后,字符串 S 变成了怎样的字符串,如果结果为空则

输出 EMPTY。

【输入格式】

输入一行包含一个字符串 S 。

【输出格式】

输出一行包含一个字符串表示答案,如果结果为空则输出 EMPTY。

【样例输入 1】

edda

【样例输出 1】

EMPTY

H: 重新排序(差分 + 前缀和 + 贪心)

给定一个数组 A 和一些查询 Li, Ri,求数组中第 Li 至第 Ri 个元素之和。

小蓝觉得这个问题很无聊,于是他想重新排列一下数组,使得最终每个查

询结果的和尽可能地大。小蓝想知道相比原数组,所有查询结果的总和最多可

以增加多少?

【输入格式】

输入第一行包含一个整数 n。

第二行包含 n 个整数 A1, A2, · · · , An,相邻两个整数之间用一个空格分隔。

第三行包含一个整数 m 表示查询的数目。

接下来 m 行,每行包含两个整数 Li、Ri ,相邻两个整数之间用一个空格分

隔。

【输出格式】

输出一行包含一个整数表示答案。

【样例输入】

5

1 2 3 4 5

2

1 3

2 5

【样例输出】

4

【样例说明】

原来的和为 6 + 14 = 20,重新排列为 (1, 4, 5, 2, 3) 后和为 10 + 14 = 24,增

加了 4。

【评测用例规模与约定】

对于 30% 的评测用例,n, m ≤ 50 ;

对于 50% 的评测用例,n, m ≤ 500 ;

对于 70% 的评测用例,n, m ≤ 5000 ;

对于所有评测用例,1 ≤ n, m ≤ 105,1 ≤ Ai ≤ 106,1 ≤ Li ≤ Ri ≤ 106 。

为了使得总和尽可能的大, 我们需要使得变化后的数组在频繁查询的区间尽可能大。

我们先统计数组中每个区间被查询到的次数, 再对数组进行排序, 使得大的数能够放到查询次数多的区间中去:

注意我们 num 定义刚开始是一个差分形式[0 ,..., 0](因为每个元素被查询到的次数都是 0, 0 - 0 = 0), 于是当查询到 [l, r], 其中涉及到到每一个位置+1, 我们的差分式就有: num[l]++, num[r + 1]--, 最后我们对 num 进行求和就得到每个位置被查询到的次数(有点像积分哈哈哈)。


蓝桥杯赛前补题(一): 2022年C/C++省赛真题个人题解的评论 (共 条)

分享到微博请遵守国家法律