[ATC复盘] abc329 20231118

[ATC复盘] abc329 20231118

    • 总结
    • A - Spread
      • 1. 题目描述
      • 2. 思路分析
      • 3. 代码实现
    • B - Next
      • 1. 题目描述
      • 2. 思路分析-
      • 3. 代码实现
    • C - Count xxx
      • 1. 题目描述
      • 2. 思路分析
      • 3. 代码实现
    • D - Election Quick Report
      • 2. 思路分析
      • 3. 代码实现
    • E - Stamp
      • 2. 思路分析
      • 3. 代码实现
    • F - Colored Ball
      • 2. 思路分析
      • 3. 代码实现
    • 六、参考链接

总结

  • 前6题除了E都挺水的。
  • A 语法题。
  • B 排序。
  • C dp计数。
  • D 贪心
  • E dp
  • F 启发式合并(模拟)

在这里插入图片描述

A - Spread

链接: A - Spread

1. 题目描述

把输入的字符串每个字符中间加空格输出。

2. 思路分析

  • join

3. 代码实现

def solve():
    s, = RS()
    print(' '.join(s))

B - Next

链接: B - Next

1. 题目描述

[ATC复盘] abc329 20231118_第1张图片

2. 思路分析-

  • 题目问出了最大之外,最大的数是哪个。
  • 就是第二大。排序即可。

3. 代码实现

def solve():
    n, = RI()
    a = sorted(set(RILST()))
    print(a[-2])

C - Count xxx

链接: C - Count xxx

1. 题目描述

[ATC复盘] abc329 20231118_第2张图片

2. 思路分析

  • 问有多少种连续相同字符的子串。如果字母a最长连续8个,那么a的连续子串有8种。
  • 那么把每种字母最长连续计数即可,我习惯用dp处理。

3. 代码实现


def solve():
    n, = RI()
    s, = RS()
    cnt = Counter([s[0]])
    f = [1] * n
    for i in range(1, n):
        if s[i] == s[i - 1]:
            f[i] += f[i - 1]
        cnt[s[i]] = max(cnt[s[i]], f[i])
    print(sum(cnt.values()))

D - Election Quick Report

链接: D - Election Quick Report
[ATC复盘] abc329 20231118_第3张图片

2. 思路分析

按顺序唱票,问当前获胜者是谁,平票取id最小的。
  • 直接计数,更新最大计数即可,注意id也一起比较。

3. 代码实现

def solve():
    n, m = RI()
    a = RILST()
    cnt = [0 for _ in range(n + 1)]
    win = [0, 0]  # 计数,-下标
    for v in a:
        cnt[v] += 1
        win = max(win, [cnt[v], -v])
        print(-win[1])

E - Stamp

链接: E - Stamp
[ATC复盘] abc329 20231118_第4张图片

2. 思路分析

已知len(t)
  • 由看到m<=5,考虑dp。
  • 令f[i][0~4]表示s[i]位置能不能匹配t[j]。那么,只有s[i]==s[j]时才能匹配,另外还要满足:
    • 如果前一个位置可以匹配t[j-1],那么这里可以匹配t[j]
    • 如果j=0,那么可以从这个位置新盖一块t。
    • 如果前一个位置可以匹配t[-1],那这里可以匹配任何位置,盖完了再盖前边即可。
    • 另外注意,地毯前后不能越界,即j<=i 且m-j<=n-i。
  • 实现时可以空间优化。
  • 注意方案必须每个位置都有匹配项,不能只判断f[-1][-1]。

3. 代码实现

def solve():
    n, m = RI()
    s, = RS()
    t, = RS()
    f = [0] * m
    f[0] = s[0] == t[0]
    for i in range(1, n):
        if not sum(f):
            return print('No')
        g = [0]*m
        for j in range(min(m, i + 1)):
            if s[i] == t[j] and m - j <= n - i:
                if j == 0 or f[m-1] or f[j-1]:
                    g[j] = 1
        f = g
    print(['No', 'Yes'][f[-1]])

def solve1():
    """
    f[i][0~4]表示前缀匹配时,s[i]是否能用t[j]来匹配
    """
    n, m = RI()
    s, = RS()
    t, = RS()
    f = [[0] * m for _ in range(n)]
    f[0][0] = s[0] == t[0]
    for i in range(1, n):
        if not sum(f[i - 1]):
            return print('No')
        for j in range(min(m, i + 1)):
            if s[i] == t[j] and m - j <= n - i:
                if j == 0:
                    f[i][j] = 1
                elif f[i - 1][m - 1]:
                    f[i][j] = 1
                elif f[i - 1][j - 1]:
                    f[i][j] = 1

    print(['No', 'Yes'][f[-1][-1]])

F - Colored Ball

链接: F - Colored Ball

[ATC复盘] abc329 20231118_第5张图片

2. 思路分析

一开始每个盒子都有一种颜色的小球,q个操作,每次把a盒子所有球倒进b盒子,问b盒子每次的球数量。
  • 语法题,启发式合并,把每次移动少的那边的盒子,然后整体给盒子动位置。
  • 启发式合并均摊复杂度是O(nlgn)的。

  • 有道类似的题,更难一些,用并查集F - BOX

3. 代码实现

#    379    ms
def solve():
    n, q = RI()
    c = [0] + RILST()
    cc = [{v} for v in c]

    for _ in range(q):
        a, b = RI()
        if len(cc[a]) > len(cc[b]):
            cc[a], cc[b] = cc[b], cc[a]
        cc[b] |= cc[a]
        cc[a] = set()
        print(len(cc[b]))


#     499   ms
def solve1():
    n, q = RI()
    c = [0] + RILST()
    cc = [{v} for v in c]

    for _ in range(q):
        a, b = RI()
        if len(cc[a]) < len(cc[b]):
            for v in cc[a]:
                cc[b].add(v)
            cc[a] = set()
        else:
            for v in cc[b]:
                cc[a].add(v)
            cc[b] = cc[a]
            cc[a] = set()
        print(len(cc[b]))

六、参考链接

你可能感兴趣的:(atcoder比赛复盘,算法)