牛客周赛 Round 47 解题报告 | 珂学家


前言

alt


题解

这真的是牛客周赛? 哭了


欢迎关注

珂朵莉 牛客周赛专栏

珂朵莉 牛客小白月赛专栏


A. 小红的葫芦

签到题

但是写起来有点变扭,方法应该蛮多的

统计分组

  • 有2组
  • 一组长度为2,一组长度为3
def check(arr):
    arr.sort()
    if arr[0] == arr[4]:
        return False
    if arr[0] == arr[1] and arr[2] == arr[4]:
        return True
    if arr[0] == arr[2] and arr[3] == arr[4]:
        return True
    return False

arr = list(map(int, input().split()))
print ("YES" if check(arr) else "NO")

B. 茉茉的密码

思路: 贪心构造

如果s满足要求,s的子串sa,必然满足要求

这样,可以贪心枚举26个字符

n = int(input())

arr = []
for _ in range(n):
    arr.append(input())
    
def check(c, arr):
    for s in arr:
        if c not in s:
            return False
    return True

for i in range(26):
    c = chr(ord('a') + i)
    if check(c, arr):
        print (c)
        break

C. 苗苗的气球

思路: 众数贪心

  • 特判n=1,n=2的情况

  • 枚举每种气球

这个时候,其实只需要讨论当前的气球A,其他的剩余B,其他中的众数C

那ABC满足什么条件,可以保证A有剩余

还要考虑奇偶,因为对消有剩余

def check(a, b, c):
    if (b + c) % 2 == 0:
        if c <= b:
            return True
        elif a > (c - b):
            return True
    else:
        if c <= b:
            return 1 if a >= 2 else 0
        elif a > (c - b):
            return True            
    return False

当然这题,还要想想如何维护众数

引入前后缀拆解, 快速求解除自身以为的众数

n = int(input())

arr = list(map(int, input().split()))

s = sum(arr)


def check(a, b, c):
    if (b + c) % 2 == 0:
        if c <= b:
            return True
        elif a > (c - b):
            return True
    else:
        if c <= b:
            return 1 if a >= 2 else 0
        elif a > (c - b):
            return True            
    return False

def solve():
    if n == 1:
        return 1
    elif n == 2:
        return 1 if arr[0] != arr[1] else 0
    pre = [0] * n
    suf = [0] * n

    # 前后缀拆解
    for i in range(1, n):
        pre[i] = max(pre[i - 1], arr[i])
    for i in range(n - 2, -1, -1):
        suf[i] = max(suf[i + 1], arr[i])

    res = 0
    for i in range(n):
        if i == 0:
            mx = suf[1]
            if check(arr[i], s - arr[i] - mx, mx):
                res += 1
        elif i == n - 1:
            mx = pre[n - 2]
            if check(arr[i], s - arr[i] - mx, mx):
                res += 1
        else:
            mx = max(pre[i - 1], suf[i + 1])
            if check(arr[i], s - arr[i] - mx, mx):
                res += 1
    return res
            
print (solve())

D. 萌萌的好数

思路: 二分+容斥+数位DP

感觉写复杂了,但是过了


# 容斥

t = int(input())

# 数位DP吗?
from functools import cache

@cache
def dfs(s, idx, acc, isLimit, isNum):
    if idx == len(s):
        return 1 if isNum and acc % 3 != 0 else 0
    r = 0
    if not isNum:
        r += dfs(s, idx + 1, 0, False, isNum)
    
    p = ord(s[idx]) - ord('0')
    if idx < len(s) - 1:
        start = 0 if isNum else 1
        end = p if isLimit else 9
        for i in range(start, end + 1):
            r += dfs(s, idx + 1, (acc+i) % 3, isLimit and i == end, True)
    else:
        if not isLimit:
            r += dfs(s, idx + 1, (acc + 3) % 3, False, True)
        else:
            if p >= 3:
                r += dfs(s, idx + 1, acc, p == 3, True)
        
    return r
        
    

def compute(x):
    z = x - x // 3
    # 最后一位为3
    s = str(x)
    m = len(s)
    
    z = z - dfs(s, 0, 0, True, False)
    dfs.cache_clear()
    return z
    
    

for _ in range(t):
    n = int(input())
    l, r = 1, n * 3
    while l <= r:
        m = (l + r) // 2
        if compute(m) < n:
            l = m + 1
        else:
            r = m - 1
    print (l)
        

E. 茜茜的计算器

思路: 容斥

横对称 + 纵对称 − ( 横 / 纵对称 ) 横对称+纵对称 -(横/纵对称) 横对称+纵对称(/纵对称)

但是这个式子太简单了

横对称的有1,3,8,0

纵对称的有25配对,52配置,00配对,88配对

n = int(input())

mod = 10 ** 9 + 7

r1 = pow(4, n, mod)
r2 = pow(4, n // 2, mod)
if n % 2 == 1:
    r2 = r2 * 2 % mod
    
r3 = pow(2, n // 2, mod)
if n % 2 == 1:
    r3 = r3 * 2 % mod

r = r1 + r2 - r3
print (r%mod)

F. 花花的地图

思路: dijkstra寻路

很典的题,之前看过的同类版本是

  • 破墙(一块)
  • 破墙(2*2)

这边是同列,因为h,w为100

这边遇到墙的时候,需要枚举一列来拓展状态点

所以大概的时间复杂度为 O ( n 3 + n 2 l o g n 2 ) O(n^3+n^2logn^2) O(n3+n2logn2)

h, w = list(map(int, input().split()))

grid = []
for _ in range(h):
    grid.append(input())
    
cost = list(map(int, input().split()))
    
from math import inf
import heapq

dp = [[inf] * w for _ in range(h)]

hp = []
if grid[0][0] == '.':
    heapq.heappush(hp, (0, 0, 0))
    dp[0][0] = 0
else:
    for i in range(h):
        heapq.heappush(hp, (cost[0], i, 0))
        dp[i][0] = cost[0]
        

while len(hp) > 0:
    c, y, x = heapq.heappop(hp)
    if c > dp[y][x]:
        continue
    
    for dy, dx in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
        ty, tx = y + dy, x + dx
        if 0 <= ty < h and 0 <= tx < w:
            if grid[ty][tx] == '.':
                if dp[ty][tx] > c:
                    dp[ty][tx] = c
                    heapq.heappush(hp, (dp[ty][tx], ty, tx))
            else:
                for j in range(h):
                    if dp[j][tx] > c + cost[tx]:
                        dp[j][tx] = c + cost[tx]
                        heapq.heappush(hp, (dp[j][tx], j, tx))

print (dp[h - 1][w - 1])

写在最后

alt

  • 11
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值