Codeforces Round 933 (Div. 3) A~F (Go语言题解)
A - Rudolf and the Ticket
题目:鲁道夫要去拜访伯纳德,他决定乘坐地铁去找他。车票可以在接受两个硬币的机器上购买,这两个硬币的总和不超过 k k k 。
鲁道夫有两个装硬币的口袋。左边口袋里有 n n n 枚面值为 b 1 , b 2 , … , b n b_1, b_2, \dots, b_n b1,b2,…,bn 的硬币。右边口袋里有 m m m 枚面值为 c 1 , c 2 , … , c m c_1, c_2, \dots, c_m c1,c2,…,cm 的硬币。他想从左边口袋和右边口袋各取出一枚硬币(共两枚)。
请帮助鲁道夫判断有多少种方法可以选择指数 f f f 和 s s s ,从而使 b f + c s ≤ k b_f + c_s \le k bf+cs≤k .
题解 :使用排序加类似于滑动窗口的滑动思想即可完成,时间复杂度 O ( m i n ( n ∗ l o g ( n ) , m ∗ l o g ( m ) ) ) O(min(n*log(n), m*log(m))) O(min(n∗log(n),m∗log(m))),主要时间消耗为排序的时间消耗
func solve() {
in := bufio.NewReader(os.Stdin)
out := bufio.NewWriter(os.Stdout)
defer out.Flush()
var t int
for Fscan(in, &t); t > 0; t-- {
var n, m, k int
Fscan(in, &n, &m, &k)
b := make([]int, n)
c := make([]int, m)
for i := range b {
Fscan(in, &b[i])
}
for i := range c {
Fscan(in, &c[i])
}
sort.Ints(b)
sort.Ints(c)
ans := 0
r := m - 1
for _, v := range b {
for r >= 0 && v+c[r] > k {
r--
}
if r < 0 {
break
}
ans += r + 1 // 累计答案
}
Fprintln(out, ans)
}
}
B - Rudolf and 121
题目:Rudolf 有一个由 n n n 个整数组成的数组 a a a ,元素的编号从 1 1 1 到 n n n 。
在一次操作中,他可以选择索引 i i i ( 2 ≤ i ≤ n − 1 2 \le i \le n - 1 2≤i≤n−1 ) 并赋值:
- a i − 1 = a i − 1 − 1 a_{i - 1} = a_{i - 1} - 1 ai−1=ai−1−1
- a i = a i − 2 a_i = a_i - 2 ai=ai−2
- a i + 1 = a i + 1 − 1 a_{i + 1} = a_{i + 1} - 1 ai+1=ai+1−1
鲁道夫可以任意多次使用这个运算。任何索引 i i i 都可以使用 0 次或更多次。
他能用这个运算使数组中的所有元素都等于零吗?
题解:可以分析得到最边缘处始终是减1的,所有从左向右遍历遇到0跳过,边缘减1,中间减2,再边缘减1,如果在这个过程中有一个数小于0即不可完成,最后特判一下最后两个元素是否为0即可,时间复杂度 O ( n ) O(n) O(n)
func solve() {
in := bufio.NewReader(os.Stdin)
out := bufio.NewWriter(os.Stdout)
defer out.Flush()
var t int
for Fscan(in, &t); t > 0; t-- {
var n int
Fscan(in, &n)
a := make([]int, n)
for i := range a {
Fscan(in, &a[i])
}
ans := true
for i := 0; i < n-2; i++ {
if a[i] == 0 {
continue
}
a[i+1] -= a[i] * 2
a[i+2] -= a[i]
if a[i+1] < 0 || a[i+2] < 0 {
ans = false
break
}
}
if a[n-2] != 0 || a[n-1] != 0 {
ans = false
}
if ans {
Fprintln(out, "YES")
} else {
Fprintln(out, "NO")
}
}
}
C - Rudolf and the Ugly String
题目:每次可以删去字符串s的某个字符问至少删去多少个,才能使得字符串中不含有子串"map" 以及 “pie”
题解:对于map, pie显然删除中间的是最好的,但是对于mapie显然删除p是最优解,所以对于发现了map或者pie时答案直接加1,然后i + 2,可以完成对于mapie这个特例的处理。时间复杂度 O ( n ) O(n) O(n)
func solve() {
in := bufio.NewReader(os.Stdin)
out := bufio.NewWriter(os.Stdout)
defer out.Flush()
var t int
for Fscan(in, &t); t > 0; t-- {
var n int
Fscan(in, &n)
s := make([]byte, n)
Fscan(in, &s)
ans := 0
for i := 0; i < n-2; i++ {
if s[i] == 'm' {
if s[i+1] == 'a' && s[i+2] == 'p' {
ans++
i += 2
}
} else if s[i] == 'p' {
if s[i+1] == 'i' && s[i+2] == 'e' {
ans++
i += 2
}
}
}
Fprintln(out, ans)
}
}
D - Rudolf and the Ball Game
题目:n个人围成环传球,可以顺时针传或者逆时针传,给定起始拿球的人 x ,以及 m次传球的距离 r1∼rm
传球的方向 c1∼cm ,问最后谁有可能接到球, c1 = 0顺时针传,c1 = 1逆时针传,c1 = ‘?’ 可以顺时针也可以逆时针传
题解:可以使用类似记忆化搜索的方式进行搜索答案,并且当i == n时记录当前的拿球位置j即可,最后对其进行排序即是答案。时间复杂度 O ( n 2 ) O(n^2) O(n2)
func solve() {
in := bufio.NewReader(os.Stdin)
out := bufio.NewWriter(os.Stdout)
defer out.Flush()
var t int
for Fscan(in, &t); t > 0; t-- {
var n, m, x int
Fscan(in, &n, &m, &x)
type node struct {
r int
c []byte
}
a := make([]node, m)
for i := range a {
Fscan(in, &a[i].r, &a[i].c)
}
res := map[int]bool{}
memo := map[pair]bool{}
var dfs func(int, int)
dfs = func(i, j int) {
if j == 0 {
j = n
}
if i == m {
res[j] = true // 记录最后可能的拿球位置
return
}
if memo[pair{i, j}] { // 当前位置已经记录过答案不在进行遍历,直接返回
return
}
if a[i].c[0] == '0' {
dfs(i+1, (j+a[i].r)%n) // 顺时针传
} else if a[i].c[0] == '1' {
dfs(i+1, (j-a[i].r+n)%n) // 逆时针传
} else {
dfs(i+1, (j+a[i].r)%n) // 顺时针传
dfs(i+1, (j-a[i].r+n)%n) // 逆时针传
}
memo[pair{i, j}] = true
}
dfs(0, x)
Fprintln(out, len(res))
ans := make([]int, 0, n)
for k := range res {
ans = append(ans, k)
}
sort.Ints(ans)
for _, v := range ans {
Fprint(out, v, " ")
}
Fprintln(out)
}
}
E - Rudolf and k Bridges
题目:伯纳德喜欢拜访鲁道夫,但他总是迟到。问题是伯纳德必须乘渡船过河。鲁道夫决定帮助他的朋友解决这个问题。
这条河是由 n n n 行和 m m m 列组成的网格。第 i i i 行和第 j j j 列的交点包含数字 a i , j a_{i,j} ai,j --相应单元格的深度。第一列和最后一列的所有单元格都对应河岸,因此它们的深度为 0 0 0 。
鲁道夫可以选择 ( i , 1 ) , ( i , 2 ) , … , ( i , m ) (i,1), (i,2), \ldots, (i,m) (i,1),(i,2),…,(i,m) 行,并在其上架桥。在该行的每个单元格中,他都可以为桥安装一个支架。在第 ( i , j ) (i,j) (i,j) 格安装支架的成本为 a i , j + 1 a_{i,j}+1 ai,j+1 。安装支架必须满足以下条件:
- 必须在单元格 ( i , 1 ) (i,1) (i,1) 中安装一个支架;
- 单元格 ( i , m ) (i,m) (i,m) 中必须安装一个支架;
- 任何一对相邻支架之间的距离不得大于 d d d 。支架 ( i , j 1 ) (i, j_1) (i,j1) 和 ( i , j 2 ) (i, j_2) (i,j2) 之间的距离为 ∣ j 1 − j 2 ∣ − 1 |j_1 - j_2| - 1 ∣j1−j2∣−1 。
只建一座桥是很无聊的。因此,鲁道夫决定在河道的连续几行上建造 k k k 座桥,即选择一些 i i i ( 1 ≤ i ≤ n − k + 1 1 \le i \le n - k + 1 1≤i≤n−k+1 ),独立建造 k k k 座桥。( 1 ≤ i ≤ n − k + 1 1 \le i \le n - k + 1 1≤i≤n−k+1 ),并在每一行 i , i + 1 , … , i + k − 1 i, i + 1, \ldots, i + k - 1 i,i+1,…,i+k−1 上独立建造一座桥。请帮助鲁道夫尽量减少安装支架的总成本。
题解:计算处每一个河流进行架桥的最小代价,然后使用前缀和计算连续的k个桥的最小代价和便是答案,对于计算每个河流进行架桥的代价计算使用单调队列的方式来进行计算,只不过此单调队列额外多了一个出队的方式那就是差值减1不能超过d,时间复杂度 O ( n ∗ m ) O(n * m) O(n∗m)
func solve() {
in := bufio.NewReader(os.Stdin)
out := bufio.NewWriter(os.Stdout)
defer out.Flush()
var t int
for Fscan(in, &t); t > 0; t-- {
var n, m, k, d int
Fscan(in, &n, &m, &k, &d)
res := make([]int, n)
for i := 0; i < n; i++ {
a := make([]int, m)
for i := range a {
Fscan(in, &a[i])
}
q := []pair{{1, m - 1}} // 单调队列
for i := m - 2; i >= 0; i-- {
for q[0].i-i-1 > d { // 差值超过了d,出队
q = q[1:]
}
p := q[0].v
if i == 0 {
break
}
for len(q) > 0 && a[i]+p+1 <= q[len(q)-1].v { // 当前代价比其他靠后的代价更小,将靠后的进行出队
q = q[:len(q)-1]
}
q = append(q, pair{a[i] + 1 + p, i})
}
res[i] = q[0].v + 1 // 最后单调队列的头加初始位置的代价为1即是架桥的代价
}
pre := make([]int, n+1)
for i := 1; i <= n; i++ {
pre[i] = pre[i-1] + res[i-1]
}
ans := math.MaxInt
for i := k; i <= n; i++ {
ans = min(ans, pre[i]-pre[i-k])
}
Fprintln(out, ans)
}
}
F - Rudolf and Imbalance
题目:鲁道夫准备了一组复杂度为 a1<a2<a3<⋯<an的 n 个问题。他对平衡并不完全满意,因此他想最多增加一个问题来解决它。
为此,鲁道夫提出了 m 个问题模型和 k 个函数。 i -th模型的复杂度是 di, j-th函数的复杂度是 fj。要创建一个问题,他需要选择值 i和 j ( 1≤i≤m, 1≤j≤k)。( 1≤i≤m, 1≤j≤k)并将 i/th 模型与 j/th 函数相结合,得到一个复杂度为 di+fj 的新问题(在数组 a 中插入了一个新元素)。
为了确定集合的不平衡性,鲁道夫将问题的复杂度按升序排序,并找出 a i − a ( i 11 ) a_i - a_(i 1 1) ai−a(i11) 的最大值( i>1 ).
鲁道夫根据所描述的规则最多添加一个问题所能达到的最小不平衡值是多少?
题解:应为只进行一次插入操作,所以需要先找到最大差值的值mx以及位置j, 再找到第二大的差值,第二大的差值基本就是最小的答案了。然后在最大差值的位置进行插入 ( d + f ) (d + f) (d+f), 且插入的值越接近 ( a j + a ( j + 1 ) ) / 2 (a_j + a_(j + 1)) / 2 (aj+a(j+1))/2 越好,时间复杂度 O ( m ∗ l o g ( k ) ) O(m * log(k)) O(m∗log(k))
func solve() {
in := bufio.NewReader(os.Stdin)
out := bufio.NewWriter(os.Stdout)
defer out.Flush()
var t int
for Fscan(in, &t); t > 0; t-- {
var n, m, k int
Fscan(in, &n, &m, &k)
a := make([]int, n)
d := make([]int, m)
f := make([]int, k)
for i := range a {
Fscan(in, &a[i])
}
for i := range d {
Fscan(in, &d[i])
}
for i := range f {
Fscan(in, &f[i])
}
sort.Ints(d)
sort.Ints(f)
mx, j, mx1 := 0, 0, 0
for i := 1; i < n; i++ {
mx1 = max(mx1, a[i]-a[i-1])
if mx1 > mx {
mx, mx1 = mx1, mx
j = i - 1
}
}
ans := mx
target := (a[j] + a[j+1]) / 2
for _, v := range d {
l, r := 0, k-1
for l+1 < r {
mid := l + (r-l)>>1
if v+f[mid] <= target {
l = mid
} else {
r = mid
}
}
ans = min(ans, max(mx1, max(abs(v+f[l]-a[j]), abs(v+f[l]-a[j+1]))))
ans = min(ans, max(mx1, max(abs(v+f[r]-a[j]), abs(v+f[r]-a[j+1]))))
}
Fprintln(out, ans)
}
}