2023ICPC济南站训练补题


title: 2023ICPC济南站VP补题记录(第48届)
date: 2024-01-18 12:16:23
mathjax: true
tags: XCPC
categories: Algorithm


文章目录

  • 2023ICPC济南站训练补题
    • 注:暂时更新vp时ac的4道题,其余题目之后持续更新
    • [Problem - D - Largest Digit](https://codeforces.com/gym/104901/problem/D)
      • 题目翻译
      • 题目分析
      • python code
    • [Problem - I - Largest Digit](https://codeforces.com/gym/104901/problem/I)
      • 题目翻译
      • 题目分析
      • Python code
    • [Problem - A - Many Many Heads](https://codeforces.com/gym/104901/problem/A)
      • 题目翻译
      • 题目分析
      • Python code
    • [Problem - G - Gifts from Knowledge](https://codeforces.com/gym/104901/problem/G)
      • 题目翻译
      • 题目分析
      • Python code
        • 扩展域并查集求解:
        • 建图按要求连边找连通块求解:

2023ICPC济南站训练补题

注:暂时更新vp时ac的4道题,其余题目之后持续更新

本人是主要Python竞赛,补题代码实现一般用python,在codeforces中,由于没未其他语言开另外时限,python提交无法ac的情况下补题给出C++实现,按难度排序。

Problem - D - Largest Digit

题目翻译

假设 f ( x ) f(x) f(x) 是正整数 x x x 的十进制表示中的最大位数。例如, f ( 4523 ) = 5 f(4523) = 5 f(4523)=5 f ( 1001 ) = 1 f(1001) = 1 f(1001)=1

给定四个整数 l a l_a la, r a r_a ra, l b l_b lb r b r_b rb 其中 l a ≤ r a l_a \le r_a lara 并且 l b ≤ r b l_b \le r_b lbrb, 计算 f ( a + b ) f(a + b) f(a+b) 的最大值( l a ≤ a ≤ r a l_a \le a \le r_a laara , , , l b ≤ b ≤ r b l_b \le b \le r_b lbbrb).

题目分析

这是一道签到题,比较简单直接上代码吧~

python code

import sys
input = sys.stdin.readline

def solve():
    la,ra,lb,rb = map(int, input().split())
    l = la+lb
    r = ra + rb
    ans = 0
    if r - l > 10:
        ans = 9
    else:
        for i in range(l,r+1):
            x = i
            while x:
                ans = max(x%10,ans)
                x //= 10
    print(ans)
for _ in range(int(input())):
    solve()

Problem - I - Largest Digit

题目翻译

在学习了 2021 国际大学生程序设计竞赛亚洲区域赛南京站的《Paimon Sorting》一题中奇怪的排序算法 后,小青鱼想到了如下的一个问题。 给定序列 a 1 , a 2 , ⋅ ⋅ ⋅ , a n a_1, a_2, · · · , a_n a1,a2,⋅⋅⋅,an 表示一个 n 的排列,您需要将该排列按升序排序,为此可以执行以下操作至多 n / 2 {n}/{2} n/2 次:选择两个下标 l 和 r 满足 1 ≤ l < r ≤ n 1 ≤ l < r ≤ n 1l<rn以及 a l > a r a_l > a_r al>ar,将 a l , a l + 1 , ⋅ ⋅ ⋅ , a r a_l , a_l+1, · · · , a_r al,al+1,⋅⋅⋅,ar 按升序进行排序。 请回忆:一个 n 的排列是一个长度为 n 的序列,每个从 1 到 n(含两端)的整数在其中都恰好出现一 次。

题目分析

这题等待队友写题解喽~

Python code

import sys
input = sys.stdin.readline

def solve():
	n = int(input())
    a = list(map(int, input().split()))
    ls = []
    for i in range(n):
        start = i
        end = i
        for j in range(i+1, n):
            if a[start] > a[j]:
                end = j
        if start != end:
            ls.append((start + 1, end + 1))
            a[start:end+1] = sorted(a[start:end+1])
    print(len(ls))
    for l, r in ls: print(l, r)

for _ in range(int(input())):
    solve()

Problem - A - Many Many Heads

题目翻译

多头杯(Multi-Heads Cup),简称 MHC,是为拥有**多头的参赛者举办的世界性编程比赛。大赛总裁判长小青鱼正在考虑为每位参赛者设计一个识别号码。

"就这样吧,"小青鱼想,"我们用一些括号序列吧!"他给每个参赛者分配了一个独一无二的平衡括号序列,括号有两种–圆括号(也叫小括号)和方括号。为了确保大家理解平衡括号序列的概念,小青鱼准备了一份平衡括号序列的正式定义:

  • ε \varepsilon ε (空字符串)是一个平衡括号序列。
  • 如果 A A A 是平衡括号序列,那么 ( A ) (A) (A) [ A ] [A] [A] 都是平衡括号序列。
  • 如果 A A A B B B 是平衡括号序列,那么 A B AB AB 也是平衡括号序列。

例如,“()”、“[()]“和”[()]() “是平衡括号序列,但”)(”、"[(]) “和”[) "不是。

对于多头参与者来说,记忆括号序列并不是一件难事。然而,挑战在于他们的独特能力:由于他们的头数太多,他们无法辨别每个括号的方向!因此,与原来的平衡括号序列相比,他们在记忆序列时可能会改变一些括号的方向。例如,括号序列"[()]() “可能会被记忆成”])) “或”]()])"。幸运的是,括号的类型保证保持不变。

2023ICPC济南站训练补题_第1张图片

比赛当天,当小青鱼收到每位参赛者的括号序列时,一个问题出现了:能否唯一地推导出原始括号序列?换句话说,小青鱼需要确定所提供的括号序列是否正好映射到一个平衡的括号序列。

请帮助 "小青鱼 "完成这项任务,这样我们的多头朋友就能参加比赛了!

题目分析

这道题很容易让我们想到栈的经典问题括号匹配,但其实感觉和这题没啥关系,主要还是考思维,我们其实很容易想到有三个连续的相同种类括号那么答案必然是 N o No No,比如 ( ) ( X ) ()(X) ()(X)必然可以条成 ( ( ) X ) (()X) (()X) ( X ) ( ) (X)() (X)()这种同理。

那么我们现在考虑两个连续的相同种类阔号:假设只有一个 ( ) 或 [ ] ()或[] ()[],其他全是交替,是满足条件的,如果有两个呢,不妨设为小括号,中括号同理,形如: A ( ) B ( ) C A()B()C A()B()C 这中类型。我们会发现只有 ( ) [ ( ) ] ()[()] ()[()] 满足条件。

综上所述,一个括号序列合法,当且仅当其不存在长度 ≥ 3 ≥3 3 的连续段,且存在不超过 2 个长度 ≥ 2 ≥2 2 的连续段。

Python code

import sys
input = sys.stdin.readline

def solve():
    s = input().strip()
    cnt = 0
    s1 = {'(',')'}
    for i in range(len(s)-1):
        if (s[i] in s1 and s[i+1] in s1) or (s[i] not in s1 and s[i+1] not in s1):
            cnt += 1
            if cnt >= 3:
                print("No")
                return
    print("Yes")

for _ in range(int(input())):
    solve()

Problem - G - Gifts from Knowledge

题目翻译

在学习了理查德-彭(Richard Peng)和桑托什-文帕拉(Santosh Vempala)的论文《比矩阵乘法更快地解决稀疏线性系统》(Solving Sparse Linear Systems Faster than Matrix Multiplication)后,小青鱼对任何稀疏的东西都很着迷。例如,稀疏矩阵。这里,稀疏矩阵指的是零元素的数量远远多于非零元素数量的矩阵。现在,小青鱼想出了一个关于二进制稀疏矩阵的问题,他想让你试着解决这个问题。

给定一个有 r r r 行和 c c c 列的二进制矩阵(只包含 0 0 0 s 和 1 1 1 s 的矩阵),你可以选择是否反转每一行。求在每列最多有一个 1 1 1 的情况下,有多少种方法可以选择一组行来反转(允许不选择任何行)。如果在其中一种方法中选择了一行,而在另一种方法中没有选择,那么这两种方法就被认为是不同的。

我们所说的颠倒行是指这样:让 i i i -th行上的元素从第一列到最后一列都是 b i , 1 , b i , 2 , ⋯   , b i , c b_{i,1}, b_{i, 2}, \cdots, b_{i, c} bi,1,bi,2,,bi,c 。如果把 i i i (th)行颠倒过来,它就变成了 b i , c , b i , c − 1 , ⋯   , b i , 1 b_{i, c}, b_{i, c - 1}, \cdots, b_{i, 1} bi,c,bi,c1,,bi,1

题目分析

如果第 j j j 列和第 ( m − j + 1 ) (m − j + 1) (mj+1) 总共的 1 的数量超过了两个, 显然无解。否则假设这两个 1 位于第 i i i 行和第 i ′ i' i 行,有两种 情况: 两个 1 处于同一列,则 i i i i ′ i' i 的选择情况是相反的。 两个 1 处于不同列,则 i i i i ′ i' i 的选择情况是相同的。 给定相同相反关系,求方案数是一个经典问题,可以通过建图来维护,当然我们也可以通过扩展域并查集来求。

Python code

扩展域并查集求解:
import sys
input = sys.stdin.readline
mod = 1000000007

def solve():
    def find(x):
        if fa[x] == x: return x
        fa[x] = find(fa[x])
        return fa[x]
    n,m = map(int, input().split())
    fa = [i for i in range(n+n)]
    ls = [list(input().strip()) for _ in range(n)]
    for i in range(m//2+1):
        l1, l2 = [], []
        if i == m-i-1:
            for j in range(n):
                if ls[j][i] == '1': l1.append(j)
            if len(l1) > 1:
                print(0)
                return
        else:
            for j in range(n):
                if ls[j][i] == '1': l1.append(j)
                if ls[j][m - i - 1] == '1': l2.append(j)
            if len(l1)+len(l2) > 2:
                print(0)
                return
        if l1 and l2:
           pa,pb = find(l1[0]),find(l2[0])
           fa[pa] = pb
           pa,pb = find(l1[0]+n),find(l2[0]+n)
           fa[pa] = pb
        elif len(l1) == 2:
            pa,pb = find(l1[0]),find(l1[1]+n)
            fa[pa] = pb
            pa,pb = find(l1[1]),find(l1[0]+n)
            fa[pa] = pb
        elif len(l2) == 2:
            pa,pb = find(l2[0]),find(l2[1]+n)
            fa[pa] = pb
            pa,pb = find(l2[1]),find(l2[0]+n)
            fa[pa] = pb
    for i in range(n):
        if find(i) == find(i+n):
            print(0)
            return
    print(pow(2,len(set(fa))//2,mod))

for _ in range(int(input())):
    solve()
建图按要求连边找连通块求解:
import sys
from collections import deque
input = sys.stdin.readline
mod = 1000000007

def solve():
    def bfs(x):
        q = deque()
        q.append(x)
        while q:
            x = q.popleft()
            if color[x]: continue
            color[x] = cnt
            for y in g[x]:
                if not color[y]: q.append(y)

    n, m = map(int, input().split())
    ls = [input().strip() for _ in range(n)]
    g = [[] for i in range(n + n)]
    for i in range(m//2+1):
        j = m - i - 1
        l1, l2 = [], []
        for k in range(n):
            if ls[k][i] == '1': l1.append(k)
            if ls[k][j] == '1': l2.append(k)
        if len(l1) + len(l2) <= 1: continue
        if i == j:
            if len(l1) >= 2:
                print(0)
                return
        else:
            if len(l1)+len(l2) > 2:
                print(0)
                return
        for a in l1:
            for b in l2:
                g[a].append(b)
                g[b].append(a)
                g[a + n].append(b + n)
                g[b + n].append(a + n)
        for a in range(len(l1)):
            for b in range(len(l1)):
                if a == b: continue
                g[l1[a]].append(l1[b] + n)
                g[l1[b] + n].append(l1[a])
                g[l1[b]].append(l1[a] + n)
                g[l1[a] + n].append(l1[b])

        for a in range(len(l2)):
            for b in range(len(l2)):
                if a == b: continue
                g[l2[a]].append(l2[b] + n)
                g[l2[b] + n].append(l2[a])
                g[l2[b]].append(l2[a] + n)
                g[l2[a] + n].append(l2[b])
    cnt = 0
    color = [0] * (n + n)
    for i in range(n + n):
        if not color[i]:
            cnt += 1
            bfs(i)
    for i in range(n):
        if color[i] == color[i + n]:
            print(0)
            return
    print(pow(2, cnt // 2, mod))


for _ in range(int(input())):
    solve()

你可能感兴趣的:(ACM-ICPC训练补题,算法,python)