前言
题解
这场感觉有点难,D完全没思路, EF很典,能够学到知识.
E我的思路是容斥+贡献,F很典,上周考过一次,引入虚拟节点质数(有点像种类并查集类似的技巧).
欢迎关注
珂朵莉 牛客周赛专栏
珂朵莉 牛客小白月赛专栏
A. 小红的整数自增
题型: 签到
贪心即可,所以值往最大值靠拢即可
arr = list(map(int, input().split()))z = max(arr)res = 0
for v in arr:res += (z - v)print (res)
B. 小红的伪回文子串(easy)
思路: 暴力
暴力枚举+模拟即可
s = input()def compute(cs):res = 0i, j = 0, len(cs) - 1while i < j:if cs[i] != cs[j]:res += 1i+=1j-=1return resn = len(s)
res = 0
for i in range(n):for j in range(i, n):res += compute(s[i:j+1])print (res)
C. 小红的01串取反
思路: 模拟
模拟即可,顺序执行相同操作
- 最后一个元素不等,即无解
- 最后一个元素相等,即有解,且按序操作最优
n = int(input())
s1 = input()
s2 = input()res = []
ss1 = list(s1)
ss2 = list(s2)for i in range(n - 1):if ss1[i] != ss2[i]:res.append([i+1, i+2])ss1[i] = '0' if ss1[i] == '1' else '1'if i + 1 < n:ss1[i+1] = '0' if ss1[i+1]=='1' else '1'if ss1[-1] != ss2[-1]:print (-1)
else:print (len(res))for (a, b) in res:print (a, b)
D. 小红的乘2除2
思路: 枚举+前后缀拆解
可以枚举除2的点,然后快速寻找那个那个点乘2收益最大
所以它的思路非常的直接
- 预处理x2的结果
- 枚举除2的点
由于不确定x2的点的位子在枚举点那一侧,所以引入前后缀拆解
这题绕的地方在于, x2和除2太接近,彼此会互相影响
所以这里需要打个补丁,即在(-1, 0, 1)的位子,特殊枚举x2的结果
这就是大致的思路
时间复杂度为 O ( n ) O(n) O(n)
n = int(input())
arr = list(map(int, input().split()))def evalute(arr):res = 0n = len(arr)for i in range(n - 1):res += abs(arr[i] - arr[i + 1])return respre = [0] * n
suf = [0] * ndef gain(i):res = 0if i >= 1:res += abs(arr[i] * 2 - arr[i - 1]) - abs(arr[i] - arr[i - 1])if i < n - 1:res += abs(arr[i] * 2 - arr[i + 1]) - abs(arr[i] - arr[i + 1])return resdef divgain(i):res = 0if i >= 1:res += abs(arr[i] // 2 - arr[i - 1]) - abs(arr[i] - arr[i - 1])if i < n - 1:res += abs(arr[i] // 2 - arr[i + 1]) - abs(arr[i] - arr[i + 1])return resfrom math import inf
pre[0] = inf
for i in range(1, n):pre[i] = min(pre[i - 1], gain(i - 1))suf[n - 1] = inf
for i in range(n - 2, -1, -1):suf[i] = min(suf[i + 1], gain(i + 1))# 前后缀拆解
from math import inf
res = inf
now = evalute(arr)def recompute(arr, i):acc = 0for k in (-1, 0, 1, 2):if i + k >= 1 and i + k < n:acc += abs(arr[i + k] - arr[i + k - 1])return accfor i in range(n):res = min(res, now + divgain(i) + min(pre[i - 1] if i >= 1 else inf, suf[i + 1] if i + 1 < n else inf)) acc = recompute(arr, i)cb = arr[i]arr[i] = cb // 2for k in (-1, 0, 1):if i + k < 0 or i + k >= n:continueold = arr[i + k]arr[i + k] = old * 2res = min(res, now + recompute(arr, i) - acc)arr[i + k] = oldarr[i] = cbprint (res)
E. 小红的伪回文子串(hard)
思路: 容斥+贡献
正难则反
正面求解很难,所以试试反向解法,就是统计相同的字符对
总的配对数 - 相同配对数
而这边的相同配对(i, j),其实有一个加权,这个加权
w = m i n ( i + 1 , n − j ) w = min(i+1, n - j) w=min(i+1,n−j)
可以先写一个 O ( n 2 ) O(n^2) O(n2)的解法
一旦写出 O ( n 2 ) O(n^2) O(n2)的解法,基本上半只脚迈入成功的道路上了
因为这里能找到一个技巧点,使得时间复杂度降为 O ( N ) O(N) O(N)
s = input()
n = len(s)# 考虑贡献法
r = 0
for i in range(n):d = i + 1x = n - 1 - iif x >= i:r += d * (x - i)r += d * (d - 1) // 2else:d2 = (n - i - 1)r += (d2 + 1) * d2 // 2hash = [[] for _ in range(26)]for (i, c) in enumerate(s):p = ord(c) - ord('a')hash[p].append(i)res = 0
for i in range(26):ls = hash[i]m = len(ls)pre = [0] * (m + 1)for j in range(m):pre[j + 1] = pre[j] + (n - ls[j])# 双指针优化tmp = 0k = m - 1for j in range(m):while k >= 0 and n - ls[k] < ls[j] + 1:k -= 1if k > j:tmp += (k - j) * (ls[j] + 1)tmp += pre[m] - pre[k + 1]else:tmp += pre[m] - pre[j + 1]res += tmp# 容斥
print (r - res)
F. 小红的迷宫行走
思路: 引入虚节点 + 0-1BFS
- 虚节点为质数
- 节点到虚节点代价为0
- 虚节点到节点代价为1
然后就跑一下0-1BFS,即可
h, w = list(map(int, input().split()))g = []
for _ in range(h):row = list(map(int, input().split()))g.append(row)from math import inf
dp = [[inf] * w for _ in range(h)]from collections import deque
from collections import defaultdict# 建图
cnt = defaultdict(list)es = [[[] for _ in range(w)] for _ in range(h)]for i in range(h):for j in range(w):k = 2v = g[i][j]while k * k <= v:if v % k == 0:cnt[k].append((i, j))es[i][j].append(k)while v % k == 0:v = v // kk += 1if v > 1:cnt[v].append((i, j))es[i][j].append(v)deq = deque()
deq.append((0, 0, 0, 0))
dp[0][0] = 0from collections import Counter
opt = Counter()from math import gcdwhile len(deq) > 0:op, y, x, c = deq.popleft()if op == 0:if y + 1 < h:if dp[y + 1][x] > c + 1:dp[y + 1][x] = c + 1deq.append((0, y+ 1, x, c + 1))if x + 1 < w:if dp[y][x + 1] > c + 1:dp[y][x + 1] = c + 1deq.append((0, y, x + 1, c+ 1))for v in es[y][x]:if v not in opt:opt[v] = cdeq.appendleft((1, v, 0, c))else:for (ty, tx) in cnt[y]:if dp[ty][tx] > c + 1:dp[ty][tx] = c + 1deq.append((0, ty, tx, c + 1))print (dp[-1][-1])