[牛客周赛复盘] 牛客周赛 Round 1 20230702
总结
- 牛客第一次,据说排名系统还在测试环境哈哈。
- A 大模拟。
- B 分类计数。
- C 贪心双指针模拟。
- D 同余dp.
游游画U
链接: 游游画U
1. 题目描述
2. 思路分析
不擅长这种画图大模拟。
- 发现前边的行全是一样的先初始化4n行。
- 然后从最后一行开始倒着覆盖,枚举中间的空格。
3. 代码实现
# Problem: 游游画U
# Contest: NowCoder
# URL: https://ac.nowcoder.com/acm/contest/60245/A
# Memory Limit: 524288 MB
# Time Limit: 2000 ms
import sys
import random
from types import GeneratorType
import bisect
import io, os
from bisect import *
from collections import *
from contextlib import redirect_stdout
from itertools import *
from array import *
from functools import lru_cache, reduce
from heapq import *
from math import sqrt, gcd, inf
if sys.version >= '3.8': # ACW没有comb
from math import comb
RI = lambda: map(int, sys.stdin.buffer.readline().split())
RS = lambda: map(bytes.decode, sys.stdin.buffer.readline().strip().split())
RILST = lambda: list(RI())
DEBUG = lambda *x: sys.stderr.write(f'{str(x)}\n')
# print = lambda d: sys.stdout.write(str(d) + "\n") # 打开可以快写,但是无法使用print(*ans,sep=' ')这种语法,需要print(' '.join(map(str, p))),确实会快。
DIRS = [(0, 1), (1, 0), (0, -1), (-1, 0)] # 右下左上
DIRS8 = [(0, 1), (1, 1), (1, 0), (1, -1), (0, -1), (-1, -1), (-1, 0),
(-1, 1)] # →↘↓↙←↖↑↗
RANDOM = random.randrange(2 ** 62)
MOD = 10 ** 9 + 7
# MOD = 998244353
PROBLEM = """
"""
def lower_bound(lo: int, hi: int, key):
"""由于3.10才能用key参数,因此自己实现一个。
:param lo: 二分的左边界(闭区间)
:param hi: 二分的右边界(闭区间)
:param key: key(mid)判断当前枚举的mid是否应该划分到右半部分。
:return: 右半部分第一个位置。若不存在True则返回hi+1。
虽然实现是开区间写法,但为了思考简单,接口以[左闭,右闭]方式放出。
"""
lo -= 1 # 开区间(lo,hi)
hi += 1
while lo + 1 < hi: # 区间不为空
mid = (lo + hi) >> 1 # py不担心溢出,实测py自己不会优化除2,手动写右移
if key(mid): # is_right则右边界向里移动,目标区间剩余(lo,mid)
hi = mid
else: # is_left则左边界向里移动,剩余(mid,hi)
lo = mid
return hi
def bootstrap(f, stack=[]):
def wrappedfunc(*args, **kwargs):
if stack:
return f(*args, **kwargs)
else:
to = f(*args, **kwargs)
while True:
if type(to) is GeneratorType:
stack.append(to)
to = next(to)
else:
stack.pop()
if not stack:
break
to = stack[-1].send(to)
return to
return wrappedfunc
# ms
def solve():
n, = RI()
ans = ['' for _ in range(4 * n)]
for i in range(4 * n):
ans[i] = ('*' * n + '.' * (2 * n) + '*' * n)
x = 0
for i in range(4 * n - 1, -1, -1):
s = ['.'] * (4 * n)
r = 4 * n // 2 + x
l = 4 * n // 2 - 1 - x
# print(l,r)
for j in range(r, r + n):
s[j] = '*'
# print(j)
for j in range(l, l - n, -1):
s[j] = '*'
x += 1
ans[i] = ''.join(s)
if x == n: break
for s in ans:
print(s)
if __name__ == '__main__':
t = 0
if t:
t, = RI()
for _ in range(t):
solve()
else:
solve()
游游的数组染色
链接: 游游的数组染色
1. 题目描述
2. 思路分析
- 数字相同的分一组,计数r和b。
- 对每种数字里,累计r*b的数量即可。
3. 代码实现
# ms
def solve():
n, = RI()
a = RILST()
cs, = RS()
cnt = defaultdict(Counter)
ans = 0
for v, c in zip(a, cs):
cnt[v][c] += 1
for v in cnt.values():
x, y = v['R'], v['B']
ans += x * y
print(ans)
游游的交换字符
链接: 游游的交换字符
1. 题目描述
2. 思路分析
需要先想到一个性质,一开始没想到卡半天去D了先。
- 题目保证一定有解。那么1和0的出现次数只差一定<=1。
- 比如01出现次数分别是x,x+1,那么最后构造的解一定是1010…101;相反就是0101…010
- 若01出现次数相同,那么构造的串可能是010101或者101010。
- 知道最终结果的话,那么题目转化成交换相邻串,如何从s变成t,这个就很典了。
- 双指针把最近的1移动到最近位置即可。
3. 代码实现
def f(s, t):
# print(s,t)
n = len(s)
j = 0
ans = 0
for i, v in enumerate(s):
while j < n and t[j] != '1':
j += 1
if v == '1':
ans += abs(i - j)
j += 1
return ans
# ms
def solve():
s, = RS()
one = s.count('1')
zero = s.count('0')
# print(one,zero)
if one == zero:
ans = min(f('01' * one, s), f('10' * one, s))
elif one > zero:
ans = f(s, '10' * zero + '1')
else:
ans = f(s, '01' * one + '0')
print(ans)
游游的9的倍数
链接: 游游的9的倍数
1. 题目描述
2. 思路分析
- 典。同余dp。
- 令f[i][j]为前i个数字组成的,子序列模9为j时的子序列个数。
- 那么添加一个数字s[i]时,尝试把前一步(*10+s[i])%9即可。
- 注意额外单独添加s[i]自己。
3. 代码实现
def solve():
s, = RS()
s = list(map(int, s))
cnt = [0] * 9
ans = 0
for v in s:
f = [0] * 9
for j, c in enumerate(cnt):
p = (j * 10 + v) % 9
if p == 0:
ans = (ans + c) % MOD
f[p] += c
if v % 9 == 0:
ans = (ans + 1) % MOD
f[v % 9] += 1
for i, v in enumerate(f):
cnt[i] = (cnt[i] + v) % MOD
print(ans)
六、参考链接
- 无