牛客春招刷题训练营-2025.3.25题解
活动地址: 牛客春招刷题训练营 - 编程打卡活动
简单题 构造C的歪
构造 a,b,c
这样一个等差数列,很容易发现 b-a=c-b
,化简可得c=2*b-a
package main
import (
"fmt"
)
func main() {
var a, b int
fmt.Scan(&a, &b)
fmt.Println(2*b - a)
}
中等题 查找两个字符串a,b中的最长公共子串
- 输入处理:
- 读取两个字符串
s
和t
- 为了简化处理,让较短的字符串作为
s
- 在字符串前加空格,便于 dp 数组处理
- 动态规划实现:
- 创建二维 DP 数组,
dp[i][j]
表示以 s[i] 和 t[j] 结尾的最长公共子串长度 - 状态转移方程:
- 当
s[i] == t[j]
时,dp[i][j] = dp[i-1][j-1] + 1
- 当
s[i] != t[j]
时,dp[i][j] = 0
- 当
- 找到最长子串:
- 遍历 dp 数组找到最大长度
maxLen
和对应的结束位置idx
- 根据结束位置和长度从原字符串中截取最长公共子串
时间复杂度:,其中 n 和 m 分别是两个字符串的长度
空间复杂度:
package main
import "fmt"
func main() {
var s, t string
fmt.Scan(&s, &t)
if len(s) > len(t) {
s, t = t, s
}
n, m := len(s), len(t)
s, t = " "+s, " "+t
dp := make([][]int, n+1)
for i := 0; i <= n; i++ {
dp[i] = make([]int, m+1)
}
for i := 1; i <= n; i++ {
for j := 1; j <= m; j++ {
if s[i] == t[j] {
dp[i][j] = dp[i-1][j-1] + 1
} else {
dp[i][j] = 0
}
}
}
maxLen, idx := 0, 0
for i := 1; i <= n; i++ {
for j := 1; j <= m; j++ {
if dp[i][j] > maxLen {
maxLen = dp[i][j]
idx = i
}
}
}
fmt.Println(s[idx-maxLen+1 : idx+1])
}
困难题 气球谜题
- 枚举颜色分组的顺序
由于只有三种颜色 {0,1,2},它们的所有排列一共就 6 种:
- 0->1->2
- 0->2->1
- 1->0->2
- 1->2->0
- 2->0->1
- 2->1->0
可以对每一种排列单独计算“将原序列染成此排列所要求的顺序”所需的最小代价,然后在 6 种结果中取最小值。
- 针对单一排列的 DP 设计
假设我们正在处理某个固定的排列,比如 0->1->2。如何计算将原序列变成“所有 0 都在左边,接着 1,最后 2”这种形态的最小花费呢?
令原序列的颜色用字符串(或数组)表示为 s,其中 。再令
表示将第 i 个元素改色的代价。
核心想法:
• 最终形成的序列从左到右只能依次出现 0 段、1 段、2 段,不能穿插倒序;一旦开始进入 1 段,就不能再回去变成 0;一旦开始 2 段,就不能再回到 0 或 1。
• 可以用 DP 来表示“处理到第 i 个元素时,我们目前染到的颜色段是哪一段”,并根据是否需要改色来累计花费。
DP 状态定义:
• :处理到第 i 个元素时,如果第 i 个元素属于目标排列的第 k 段(
),所需的最小总花费。
• 例如在排列 0->1->2 里,k=0 代表当前染成颜色 0,k=1 代表当前染成颜色 1,k=2 代表当前染成颜色 2。
状态转移:
1. 第 i 个元素的实际颜色为 ,目标颜色为排列中的第 k 段颜色(记作
)。
2. 若 ,则第 i 个元素不需要改色;否则需要花费
。
3. 第 i 个元素想要染成第 k 段,必须保证上一个元素(i-1)所处的段 j 不大于 k(即 ),因为不能“往回走”去染成之前的颜色段。
于是有:
其中
-
如果当前字符与目标位置字符相同,不需要额外代价
-
如果不同,需要支付 t[i] 的代价来修改
- 综合 6 种排列取最小
对 6 种排列分别执行上述 DP,得到 6 个花费结果,最后取最小值即可。
注意:这题因为读入量过大,建议使用 bufio.NewReader
读入优化。
package main
import (
"bufio"
"fmt"
"math"
"os"
)
func min(a, b int64) int64 {
if a < b {
return a
}
return b
}
func main() {
in := bufio.NewReader(os.Stdin)
out := bufio.NewWriter(os.Stdout)
defer out.Flush()
var (
n int
s string
)
fmt.Fscan(in, &n, &s)
s = " " + s
t := make([]int64, n+1)
for i := 1; i <= n; i++ {
fmt.Fscan(in, &t[i])
}
f := func(ss string) int64 {
dp := make([][3]int64, n+1)
for i := 1; i <= n; i++ {
for j := 0; j < 3; j++ {
dp[i][j] = 1e18
}
}
for i := 1; i <= n; i++ {
for j := 0; j < 3; j++ {
for k := j; k < 3; k++ {
if s[i] == ss[k] {
dp[i][k] = min(dp[i][k], dp[i-1][j])
} else {
dp[i][k] = min(dp[i][k], dp[i-1][j]+t[i])
}
}
}
}
var ans int64 = math.MaxInt64
for j := 0; j < 3; j++ {
ans = min(ans, dp[n][j])
}
return ans
}
fmt.Fprintln(out, min(min(min(min(min(f("012"), f("021")), f("102")), f("120")), f("201")), f("210")))
}
#牛客春招刷题训练营##牛客激励计划#爱丽姐真是太好了