Codeforces Round 894 (Div. 3) (A~G)题解

Codeforces Round 894 (Div. 3)

A. Gift Carpet

动态规划 贪心 模拟 字符串

A. 题意

给定一个 n × m n \times m n×m 由小写字母组成的网格

判断是否可以从不同列中各选一个字母,有序地组成 vika

A. 题解

模拟:按列扫描网格。指针一开始指向字母 v 。如果该列中含有指针所指向的字母,则移动指针,开始新一列的扫描。扫描完成后,判断指针是否移动到字符串的末尾。

贪心:选择字母 v 在哪一列时,越靠左越好。因为此时选择字母 i 时可选择的范围最大。其他字母类似。

B. Sequence Game

构造

B. 题意

正整数序列 A = a 1 , a 2 … a n A = a_1,a_2 \dots a_n A=a1,a2an

序列 B B B 由序列 A A A 产生,规则如下:

  1. a 1 ∈ B a_1 \in B a1B
  2. 如果 a i ≥ a i − 1 a_i \ge a_{i - 1} aiai1 a i ∈ B a_i \in B aiB

现给出序列 B B B ,求一可能的序列 A A A ,要求 ∣ A ∣ ≤ 2 ∣ B ∣ |A| \le 2|B| A2∣B

B. 题解

构造:考虑 b i b_i bi b i + 1 b_{i + 1} bi+1 之间是否要插入新的元素

  • 如果 b i + 1 ≥ b i b_{i + 1} \ge b_{i} bi+1bi a i = b i , a i + 1 = b i + 1 a_i = b_i, a_{i + 1} = b_{i + 1} ai=bi,ai+1=bi+1 是一个可行的方案,不用往这两个元素之间插入新的元素
  • 如果 b i + 1 < b i b_{i + 1} < b_{i} bi+1<bi 则说明其之间存在一个元素,使得 x < b i , b i + 1 > = x x < b_i, b_{i + 1} >= x x<bi,bi+1>=x ,只需令 x = 1 x = 1 x=1 即可

C. Flower City Fence

二分查找 数据结构 模拟 排序

C. 题意

给定一不增序列 A = a 1 , a 2 … a n A = a_1,a_2 \dots a_n A=a1,a2an

a i a_i ai 表示一个宽为 1 1 1 ,长为 a i a_i ai 的矩形

将其有序排在一起,判断其所构成的图形是否为以对角线为轴的轴对称图形

例子:

A = { 5 , 4 , 3 , 2 , 1 } A = \{5,4,3,2,1\} A={5,4,3,2,1}

在这里插入图片描述

C. 题解

如果其为轴对称图形,则下图中红线和黄线部分长度相等

在这里插入图片描述

从右往左遍历,依次统计黄线的长度,存入 B B B

判断 a i a_i ai 是否等于 b i b_i bi ,如果全部都相等,则为轴对称图形

D. Ice Cream Balls

二分查找 组合 构造 数学

D. 题意

给定一个正整数 n ( 1 ≤ n ≤ 1 0 18 ) n (1 \le n \le 10^{18}) n(1n1018)

求最少需要多少个数,使得由其组合而来的无序数对的个数恰好等于 n n n

例如: 1 , 1 , 2 {1, 1, 2} 1,1,2 可以组成的无序数对有: ( 1 , 1 ) , ( 1 , 2 ) (1, 1), (1, 2) (1,1),(1,2)

D. 题解

  • 如果选择了 n n n 个不同的数,那么无序数对的个数为 n ( n − 1 ) 2 \frac{n(n - 1)}{2} 2n(n1)
  • 如果此时选了一个已有的数,那么无序数对的个数多加 1 1 1
  • 如果此时再选一个已有的数,那么无序数对的个数不再增加

综上,我们可以先选择 n n n 个不同的数,再从中选择若干个相同的数,使得无序数对的个数等于 n n n

考虑第一步的实现方法:二分。 1 , 3 , 6 , 10 … x ( x − 1 ) 2 1, 3, 6, 10 \dots \frac{x(x-1)}{2} 1,3,6,102x(x1) 上二分第一个小于等于 n n n 的数 x x x

答案为: x + ( n − x ( x − 1 ) 2 ) x + (n - \frac{x(x-1)}{2}) x+(n2x(x1))

E. Kolya and Movie Theatre

构造 数据结构 贪心

E. 题意

给定一长度为 n n n 数列 A = a 1 , a 2 … a n A = a_1, a_2 \dots a_n A=a1,a2an

给定正整数 m , d m, d m,d

你需要从序列 A A A 中至多选择 m m m 个元素,使得下列式子值最大:

∑ a i − ( p i − p i − 1 ) ⋅ d \sum a_i - (p_i - p_{i - 1}) \cdot d ai(pipi1)d

其中 p i p_i pi 表示你所选择的第 i i i 个元素的下标

E. 题解

注意到,我们可以将式子分成两个部分考虑:

∑ a i \sum a_i ai ∑ p i − p i − 1 ⋅ d \sum p_i - p_{i - 1} \cdot d pipi1d

考虑第二个式子,我们可以将其展开:

∑ p i − p i − 1 ⋅ d = d ( p 1 − 0 + p 2 − p 1 … p n − p n − 1 ) = d ⋅ p n \sum p_i - p_{i - 1} \cdot d = d (p_1 - 0 + p_2 - p1 \dots p_n - p_{n - 1}) = d \cdot p_n pipi1d=d(p10+p2p1pnpn1)=dpn

发现,第二个式子的值只与所选择的最后一个元素的位置有关

于是,我们用小根堆维护第一个式子的最大值,当堆的个数小于 m m m 时,直接插入 a i a_i ai ;当堆顶元素小于 a i a_i ai 时,用 a i a_i ai 替换堆顶元素

每次操作后,用 ∑ − d ⋅ p \sum - d \cdot p dp 更新答案, ∑ \sum 表示第一个和式的值, d ⋅ p d \cdot p dp 表示第二个式子的值

F. Magic Will Save the World

二分查找 位运算 暴力 动态规划

F. 题意

n n n 个怪兽,血量为 s 1 , s 2 ⋯ s n s_1,s_2 \cdots s_n s1,s2sn

每秒你可以获得 w w w 点水系魔法点和 f f f 点火系魔法点

同时,你可以消耗 x x x 点魔法点释放伤害为 x x x 的法术

当你对某个怪兽造成的伤害大于等于其血量时,其将会被消灭

注意,同一只怪兽只会受到同一种属性的伤害

求消灭所有怪兽的最短时间

F. 题解

发现:我们可以先积攒魔法点,再一次性消灭所有的怪兽,而不是考虑如何一边积攒一边消灭怪兽

S = ∑ s i S = \sum s_i S=si x x x 为积攒的水系魔法点, y y y 为积攒的火系魔法点

x + y ≥ S x + y \ge S x+yS 的时候,我们便可以一次性消灭所有的怪兽

此时所用的时间为 max ⁡ ( ⌈ x w ⌉ , ⌈ y f ⌉ ) \max(\left\lceil\frac{x}{w}\right\rceil, \left\lceil\frac{y}{f}\right\rceil) max(wx,fy)

首先我们计算 S = ∑ s i S = \sum s_i S=si 然后枚举所有合法的 x x x 的值,用 S − x S - x Sx 求出相应的 y y y 的值后不断更新答案

考虑如何求出所有可能的 x x x 的值:

假设怪兽的血量为: 2 , 6 , 7 2, 6, 7 2,6,7

版本1:

0 0 0 ,第一只怪兽的血量为 2 2 2 ,更新: 0 , 0 + 2 = 2 0, 0 + 2 = 2 0,0+2=2

0 , 2 0, 2 0,2 ,第二只怪兽的血量为 6 6 6 ,更新: 0 , 2 , 0 + 6 , 2 + 6 0, 2, 0 + 6, 2 + 6 0,2,0+6,2+6 ,得到 0 , 2 , 6 , 8 0, 2, 6, 8 0,2,6,8

同理,最后我们可以得到所有可能的 x x x 的值为: 0 , 2 , 7 , 9 , 13 , 15 0, 2, 7, 9, 13, 15 0,2,7,9,13,15

考虑这种方法的复杂度,其复杂度为: O ( n S ) O(nS) O(nS) ,估算一下为: 1 0 2 × 1 0 2 × 1 0 4 = 1 0 8 10^2 \times 10^2 \times 10^4 = 10^8 102×102×104=108 可能过不了

版本2:

上述过程,我们可以用 bitset 来优化加速

想象一个 1 0 6 10^6 106 位的二进制数字, 1 1 1 表示是一个合法的 x x x 0 0 0 表示不是一个合法的 x x x

每次用 s i s_i si 更新时,相当于进行一次左移运算再加上一次或运算

0000   0000   0000   0001 0000~0000~0000~0001 0000 0000 0000 0001 表示 0 0 0 是一个合法的 x x x

2 2 2 更新,相当于 0000   0000   0000   0100 0000~0000~0000~0100 0000 0000 0000 0100 (进行一次左移运算)与 0000   0000   0000   0001 0000~0000~0000~0001 0000 0000 0000 0001 (原来)进行一次或运算,其结果为 0000   0000   0000   0101 0000~0000~0000~0101 0000 0000 0000 0101 表示 0 , 2 0,2 0,2 均是一个合法的 x x x

同理我们可以用其他的 s i s_i si 更新,最后遍历,每个二进制位,如果该位为 1 1 1 就更新答案

G. The Great Equalizer

二分查找 数据结构 数学 排序

G. 题意

给定一个长度为 n n n 的序列 A = a 1 , a 2 ⋯ a n A = a_1,a_2 \cdots a_n A=a1,a2an

定义操作1如下:

  1. A A A 从小到大排序,并删除重复的元素,假设此时 A A A 的长度变为 m m m
  2. 将序列 A A A 更新为 { a 1 + m , a 2 + m − 1 , a 3 + m − 2 ⋯ a m + 1 } \{a_1 + m, a_2 + m-1, a_3 + m-2 \cdots a_m + 1\} {a1+m,a2+m1,a3+m2am+1}
  3. 不断重复操作1和操作2,直到序列 A A A 中只剩下一个元素,你需要输出该元素的值

定义操作2如下:

  1. 每次操作给定两个整数 x , y x, y x,y ,其含义为:将 a x a_x ax 修改为 y y y

现依次执行 q q q 次操作2,求每次操纵2后,假如执行操作1后剩下的值

G. 题解

首先考虑给定一个序列 A A A ,经过操作1后剩下的数是什么

发现,操作1中每次更新只会使相邻元素的差减一,从而可以发现, A A A 中最大的元素会更新 A A A 差分的最大值,而 A A A 中最大元素每次更新是加一,从而可以得出 A A A 中最后剩下的元素为 A A A 的最大的元素加上 A A A 差分的最大值( A A A 中最大的元素一直在最右边,从右往左一直合并)

于是,问题变成了:我们需要维护这样的一个东西,可以高效地查询操作2执行后, A A A 中的最大值和 A A A 差分的最大值

我们可以利用两个 multiset 来维护这两个值

考虑如何用 multiset 维护序列 A A A 的最大值,显然,直接删除 a x a_x ax 然后加入 y y y 即可。

考虑如何用 multiset 维护序列 A A A 差分的最大值:

  1. 当修改 a x a_x ax 时,我们需要:
    • 删除 a x a_x ax 与其前继的差分
    • 删除 a x a_x ax 的后继与其的差分
    • 加入 a x a_x ax 的后继与其前继的差分
    • (注意,需要判断 a x a_x ax 是否有前继、后继)
  2. 让后我们找到插入 y y y 的位置,同理:
    • 加入 y y y 与其前继的差分
    • 加入 y y y 其后继与其的差分
    • 删除 y y y 的后继与其前继的差分
    • (注意,此时我们也需要判断 y y y 是否有前继、后继)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值