A题 (A.go
)
思路总结: 这道题要求判断一个整数中是否包含连续的两个'9'。
核心思路是将输入的整数转换为字符串,然后遍历这个字符串,检查是否存在相邻的两个字符都是'9'。如果找到了,就立即停止遍历并输出"YES";如果遍历完整个字符串都没有找到,则输出"NO"。
// ==========================================================
// POWERED BY GMJ
// 2025-07-06 18:26
// ==========================================================
// Github: https://github.com/Joker-0111-G
// CSDN: https://blog.csdn.net/dl999666?type=blog
// Gmail: joker0111gmj@gmail.com
// Author: USER <joker0111gmj@gmail.com>
// FilePath: ~/homegmj/GoCode/NK/20250706\A.go
// License: MIT
// Copyright: (c) 2025 JOKER. All rights reserved.
// ==========================================================
// __ __ _ _____ _ _ ____ __ __ _
// \ \/ / / \|_ _| | | |/ ___| \/ | | |
// \ / / _ \ | | | | | | | _| |\/| |_ | |
// / \ / ___ \| | | |_| | |_| | | | | |_| |
// /_/\_\/_/ \_\_| \___/ \____|_| |_|\___/
// ==========================================================
// Project Description (use | for new lines)package mainimport ("fmt""strconv"
)func mainA() {var n intfmt.Scan(&n) s := strconv.Itoa(n)found99 := false for i := 0; i < len(s)-1; i++ {if s[i] == '9' && s[i+1] == '9' {found99 = true break }}if found99 {fmt.Println("YES") } else {fmt.Println("NO") }
}
B题 (B.go
)
思路总结: 题目要求找到输入字符串中ASCII码最大的字符,并输出其ASCII码值。
解法非常直接:初始化一个变量ma
为0,用来记录当前遇到的最大ASCII码。然后遍历输入字符串中的每一个字符,将其转换为对应的ASCII整数值。在遍历过程中,如果当前字符的ASCII值大于ma
,就更新ma
。遍历结束后,ma
中存储的就是整个字符串中最大的ASCII码值,直接输出即可。
// ==========================================================
// POWERED BY GMJ
// 2025-07-06 19:02
// ==========================================================
// Github: https://github.com/Joker-0111-G
// CSDN: https://blog.csdn.net/dl999666?type=blog
// Gmail: joker0111gmj@gmail.com
// Author: USER <joker0111gmj@gmail.com>
// FilePath: ~/homegmj/GoCode/NK/20250706\B.go
// License: MIT
// Copyright: (c) 2025 JOKER. All rights reserved.
// ==========================================================
// __ __ _ _____ _ _ ____ __ __ _
// \ \/ / / \|_ _| | | |/ ___| \/ | | |
// \ / / _ \ | | | | | | | _| |\/| |_ | |
// / \ / ___ \| | | |_| | |_| | | | | |_| |
// /_/\_\/_/ \_\_| \___/ \____|_| |_|\___/
// ==========================================================
// Project Description (use | for new lines)package mainimport ("bufio""fmt""os"
)func mainB() {reader := bufio.NewReader(os.Stdin)var T intfmt.Fscan(reader, &T) for t := 0; t < T; t++ {var n intfmt.Fscan(reader, &n) var s stringfmt.Fscan(reader, &s)ma := 0 for _, char := range s {as := int(char)if as > ma {ma = as}}fmt.Println(ma) }
}
C题 (C.go
)
思路总结: 这道题的目标是构造一个由'4'和'8'组成的、总价值为k
的最小数字。"4"的价值是1,"8"的价值是2。
为了让构造出的数字最小,位数应该尽可能少。因为'8'的价值(2)是'4'的价值(1)的两倍,所以应该优先使用'8'来减少位数。
具体策略是:
-
将
k
对2进行整除,商a
表示需要多少个'8'。 -
k
对2取模,如果余数为1 (b=true
),说明还需要一个价值为1的'4'。 -
为了使数字最小,较小的数字'4'应该放在较高的位(即最前面)。所以,如果需要'4',就先在结果中添加一个'4'。
-
然后,在后面追加
a
个'8'。 -
特殊情况:如果
k=0
,价值为0,无法用'4'或'8'表示,但题目可能要求输出一个有效数字,根据代码逻辑,此时输出'1'(可能是题目特定要求或默认值)。
// ==========================================================
// POWERED BY GMJ
// 2025-07-06 19:04
// ==========================================================
// Github: https://github.com/Joker-0111-G
// CSDN: https://blog.csdn.net/dl999666?type=blog
// Gmail: joker0111gmj@gmail.com
// Author: USER <joker0111gmj@gmail.com>
// FilePath: ~/homegmj/GoCode/NK/20250706\C.go
// License: MIT
// Copyright: (c) 2025 JOKER. All rights reserved.
// ==========================================================
// __ __ _ _____ _ _ ____ __ __ _
// \ \/ / / \|_ _| | | |/ ___| \/ | | |
// \ / / _ \ | | | | | | | _| |\/| |_ | |
// / \ / ___ \| | | |_| | |_| | | | | |_| |
// /_/\_\/_/ \_\_| \___/ \____|_| |_|\___/
// ==========================================================
// Project Description (use | for new lines)package mainimport ("bufio""fmt""os""strings"
)func mainC() {reader := bufio.NewReader(os.Stdin)writer := bufio.NewWriter(os.Stdout)defer writer.Flush() var T intfmt.Fscan(reader, &T) for i := 0; i < T; i++ {var k intfmt.Fscan(reader, &k) if k == 0 {fmt.Fprintln(writer, 1) continue}a := k / 2b := (k % 2 == 1)var res strings.Builder if b {res.WriteByte('4') }for j := 0; j < a; j++ {res.WriteByte('8')}fmt.Fprintln(writer, res.String()) }
}
D题 (D.go
)
思路总结: 这是一道数学或逻辑推导题。给定x
和p
,需要计算一个结果。
通过分析代码逻辑 a := p / x
和 b := p - a
,我们可以推断这可能与某种分配或分组有关。 核心判断在于 p % x == 0
:
-
如果
p
能被x
整除,结果是2*a - 1
。这里的a
就是p/x
。 -
如果
p
不能被x
整除,结果是2 * b
。这里的b
是p - p/x
。
这暗示了两种不同的计算场景。在能整除的情况下,可能存在某种合并或特殊状态,导致结果减1。在不能整除的情况下,则是基于p
和商a
的差值进行计算。解题的关键是理解这两种情况对应的具体数学模型。
// ==========================================================
// POWERED BY GMJ
// 2025-07-06 19:10
// ==========================================================
// Github: https://github.com/Joker-0111-G
// CSDN: https://blog.csdn.net/dl999666?type=blog
// Gmail: joker0111gmj@gmail.com
// Author: USER <joker0111gmj@gmail.com>
// FilePath: ~/homegmj/GoCode/NK/20250706\D.go
// License: MIT
// Copyright: (c) 2025 JOKER. All rights reserved.
// ==========================================================
// __ __ _ _____ _ _ ____ __ __ _
// \ \/ / / \|_ _| | | |/ ___| \/ | | |
// \ / / _ \ | | | | | | | _| |\/| |_ | |
// / \ / ___ \| | | |_| | |_| | | | | |_| |
// /_/\_\/_/ \_\_| \___/ \____|_| |_|\___/
// ==========================================================
// Project Description (use | for new lines)package mainimport ("bufio""fmt""os"
)func mainD() {reader := bufio.NewReader(os.Stdin)writer := bufio.NewWriter(os.Stdout)defer writer.Flush() var T intfmt.Fscan(reader, &T) for i := 0; i < T; i++ {var x, p intfmt.Fscan(reader, &x, &p) a := p / x b := p - avar res intif p%x == 0 {res = 2*a - 1}else{res = 2 * b}fmt.Fprintln(writer, res) }
}
E题 (E.go
)
思路总结: 这道题是一道动态规划(DP)问题。目标是求解对一个数组进行操作后,需要移除多少个只出现一次的元素。
问题可以转化为:最多能保留多少个只出现一次的元素。
我们定义DP状态:
-
dp0
: 表示处理到第i
个元素时,不选择第i
个元素能保留的最多独特元素数量。 -
dp1
: 表示处理到第i
个元素时,选择第i
个元素(前提是a[i]
是独特元素且满足某种条件)能保留的最多独特元素数量。
状态转移方程: 遍历数组 a
从 1
到 n
:
-
计算
next_dp0
(不选当前元素a[i-1]
):-
可以从
dp0
(前一个也不选) 转移而来。 -
也可以从
dp1
(前一个选了) 转移而来,只要满足不冲突的条件 (如a[i-2] < i
)。 -
next_dp0 = max(dp0, dp1_if_valid)
-
-
计算
next_dp1
(选择当前元素a[i-1]
):-
首先,
a[i-1]
必须是只出现一次的元素。 -
可以从
dp0
转移:dp0 + 1
,需满足条件 (如i-1 < a[i-1]
)。 -
可以从
dp1
转移:dp1 + 1
,需满足条件 (如a[i-2] < a[i-1]
)。 -
next_dp1 = max(dp0_to_dp1, dp1_to_dp1)
-
遍历结束后,max(dp0, dp1)
就是最多能保留的独特元素数量 maxLen
。
最终答案是 总的独特元素数量 - maxLen
。
// ==========================================================
//
// POWERED BY GMJ
// 2025-07-06 19:18
//
// ==========================================================
// Github: https://github.com/Joker-0111-G
// CSDN: https://blog.csdn.net/dl999666?type=blog
// Gmail: joker0111gmj@gmail.com
// Author: USER <joker0111gmj@gmail.com>
// FilePath: ~/homegmj/GoCode/NK/20250706/E_fixed.go
// License: MIT
// Copyright: (c) 2025 JOKER. All rights reserved.
// ==========================================================
//
// __ __ _ _____ _ _ ____ __ __ _
// \ \/ / / \|_ _| | | |/ ___| \/ | | |
// \ / / _ \ | | | | | | | _| |\/| |_ | |
// / \ / ___ \| | | |_| | |_| | | | | |_| |
// /_/\_\/_/ \_\_| \___/ \____|_| |_|\___/
//
// ==========================================================
package mainimport ("bufio""fmt""os""strconv"
)var (in = bufio.NewScanner(os.Stdin)out = bufio.NewWriter(os.Stdout)negInf = -1 << 30
)func init() {in.Split(bufio.ScanWords)
}func readInt() int {in.Scan()n, _ := strconv.Atoi(in.Text())return n
}func max(a, b int) int {if a > b {return a}return b
}func solve() {n := readInt()a := make([]int, n)freq := make(map[int]int)for i := 0; i < n; i++ {val := readInt()a[i] = valfreq[val]++}numTotalUnique := len(freq)isUnique := make(map[int]bool)for val, count := range freq {if count == 1 {isUnique[val] = true}}dp0 := 0dp1 := negInffor i := 1; i <= n; i++ {a_i := a[i-1]ndp0_from_dp0 := dp0ndp0_from_dp1 := negInfif i > 1 {if a[i-2] < i {ndp0_from_dp1 = dp1}}next_dp0 := max(ndp0_from_dp0, ndp0_from_dp1)next_dp1 := negInfif isUnique[a_i] {ndp1_from_dp0 := negInfif i-1 < a_i {ndp1_from_dp0 = dp0 + 1}ndp1_from_dp1 := negInfif i > 1 {if a[i-2] < a_i {ndp1_from_dp1 = dp1 + 1}}next_dp1 = max(ndp1_from_dp0, ndp1_from_dp1)}dp0 = next_dp0dp1 = next_dp1}maxLen := max(dp0, dp1)fmt.Fprintln(out, numTotalUnique-maxLen)
}func mainE() {defer out.Flush()t := readInt()for t > 0 {solve()t--}
}
F题 (F.go
)
思路总结: 这道题要求在满足特定条件下找到一个最大的整数 h
。条件是:n
可以表示为 m
个数 x_i
的和(n = x_1 + ... + x_m
),其中每个 x_i
都大于等于 h
,并且 x_i
和 h
的按位与(bitwise AND)都为0。
核心思路是贪心 + 位运算检验。
-
贪心策略: 从高位到低位(例如从第30位开始)尝试构建
h
。我们希望h
尽可能大,所以优先尝试将高位置为1。 -
构建过程:
-
初始化答案
ans = 0
。 -
从
b = 30
到0
循环。 -
在每一位
b
,我们尝试将ans
的第b
位置为1,形成一个临时的h
,即h = ans | (1 << b)
。
-
-
检验可行性:
-
将每个
x_i
分解为h + y_i
。因为x_i & h == 0
,所以x_i >= h
等价于y_i >= 0
且y_i & h == 0
。 -
原方程
n = sum(x_i)
变为n = sum(h + y_i) = m*h + sum(y_i)
。 -
我们需要检验
rem = n - m*h
(剩余部分) 是否能被分配到m
个y_i
中,同时满足y_i >= 0
和y_i & h == 0
。 -
这个检验过程由
check(rem, m, h)
函数完成。
-
-
check函数逻辑:
-
该函数通过从高位到低位逐位处理
rem
来判断分配是否可能。 -
它维护一个
debt
(债务)变量。对于rem
的每一位,如果h
的对应位是1,那么y_i
的这一位必须是0,所以rem
在这一位的1不能被分配,会累积成“债务”传递给更低的位。 -
如果
h
的对应位是0,那么y_i
的这一位可以是1,我们可以用这m
个数来“偿还”债务。最多可以偿还m
。 -
如果在任何时候债务过大(溢出风险),或者到最后债务没有清零,则说明分配失败。
-
-
更新答案:
-
如果
check
函数返回true
,说明将第b
位置为1是可行的,我们更新ans = h
。 -
否则,保持
ans
不变,继续尝试下一位。
-
最终得到的 ans
就是满足条件的最大 h
。
// ==========================================================
// POWERED BY GMJ
// 2025-07-06 19:25
// ==========================================================
// Github: https://github.com/Joker-0111-G
// CSDN: https://blog.csdn.net/dl999666?type=blog
// Gmail: joker0111gmj@gmail.com
// Author: USER <joker0111gmj@gmail.com>
// FilePath: ~/homegmj/GoCode/NK/20250706\F.go
// License: MIT
// Copyright: (c) 2025 JOKER. All rights reserved.
// ==========================================================
// __ __ _ _____ _ _ ____ __ __ _
// \ \/ / / \|_ _| | | |/ ___| \/ | | |
// \ / / _ \ | | | | | | | _| |\/| |_ | |
// / \ / ___ \| | | |_| | |_| | | | | |_| |
// /_/\_\/_/ \_\_| \___/ \____|_| |_|\___/
// ==========================================================
// Project Description (use | for new lines)package mainimport ("bufio""fmt""os"
)// max devuelve el mayor de dos enteros int64.
func max(a, b int64) int64 {if a > b {return a}return b
}// check determina si 'rem' (el resto) se puede escribir como la suma
// de 'm' enteros no negativos, donde cada uno es bitwise ortogonal a 'h'.
func check(rem int64, m int64, h int64) bool {var debt int64 = 0 // 'debt' acumula la deuda desde los bits más significativos.// Iteramos desde un bit alto para manejar cualquier acarreo de forma segura.for j := 62; j >= 0; j-- {// Si ya no quedan bits en 'rem' y la deuda es cero, podemos parar.if debt == 0 && (rem>>j) == 0 {continue}// Si la deuda es demasiado grande, es imposible que se pague.// Esto previene el desbordamiento (overflow) de 'debt'.// 1<<62 es una cota segura que está por debajo del límite de int64.if debt >= (1 << 62) {return false}// Acumulamos la deuda, desplazándola e incluyendo el bit actual de 'rem'.debt = debt*2 + (rem>>j)&1// Si el bit j está "permitido" (h_j == 0), podemos usar nuestros 'm'// créditos para pagar la deuda.if (h>>j)&1 == 0 {debt = max(0, debt-m)}}// Si al final del proceso la deuda es cero, la distribución es posible.return debt == 0
}func mainF() {in := bufio.NewReader(os.Stdin)out := bufio.NewWriter(os.Stdout)defer out.Flush()var T intfmt.Fscan(in, &T)for t := 0; t < T; t++ {var n, m int64fmt.Fscan(in, &n, &m)var ans int64 = 0// Estrategia greedy: construir la respuesta desde el bit más significativo (30).for b := 30; b >= 0; b-- {h := ans | (1 << b)// Si m*h > n, es imposible. Usamos n/m para evitar desbordamientos.if h > n/m {continue}rem := n - m*h// Verificamos si este resto se puede distribuir correctamente.if check(rem, m, h) {// Si es posible, aceptamos este bit.ans = h}}fmt.Fprintln(out, ans)}
}