ACM训练补题(2022ICPC沈阳站)python题解
这里给出部分题解(个人结题记录,可能还有很多地方可以优化),持续更新中,按对我个人的难度排序
记得用PyPy3.x交,比python3.x系列会快几倍
D、DRX vs. T1
签到题,按题意模拟即可
import sys
s = list(sys.stdin.readline().strip())
d, t = 0, 0
for i in range(len(s)):
if s[i] == 'T': t += 1
elif s[i] == 'D': d += 1
if d ==3 or t == 3: break
print("T1" if t == 3 else "DRX")
C、Clamped Sequence
简单题,分析可知区间限制在 [ l,r]只会使sum变小,所以我们要使 l 到 r 之间尽可能包含多的数,所以 r = l + d,每个 |ai − ai+1| 对答案的贡献是关于 l 的分段一次函数,可以枚举 O(n) 个关键的 l 和 r 计算答案,做到 O(n^2 ) 的复杂度,也可以使用扫描线维护做到 O(n logn) 的复杂度。
这里给出O(n^2)的代码:
import sys
n,d = map(int, sys.stdin.readline().split())
a = list(map(int, sys.stdin.readline().split()))
ls = [0]*n
ans = -1
for j in range(n):
l = a[j]
r = l+d
cnt = 0
for i in range(n):
if a[i] < l: ls[i] = l
elif a[i] > r: ls[i] = r
else: ls[i] = a[i]
for i in range(n-1):
cnt += abs(ls[i]-ls[i+1])
ans = max(cnt, ans)
for j in range(n):
r = a[j]
l = r-d
cnt = 0
for i in range(n):
if a[i] < l: ls[i] = l
elif a[i] > r: ls[i] = r
else: ls[i] = a[i]
for i in range(n-1):
cnt += abs(ls[i]-ls[i+1])
ans = max(cnt, ans)
print(ans)
L、Tavern Chess
一个模拟题,当时自己先统计不同结果的局数来模拟写的WA了比较蛋疼,后来直接在dfs中算概率AC了。酒馆战旗规则,所有随从都是初始生命等于攻击的水桶腰身材,可以发现任何两个随从对撞时至少有一个被击倒。 递归遍历所有可能的局面,遍历到的局面最多是 (7!)^2。
下面直接上ac代码吧,没分太多函数,可能写的比较累赘。
import sys
sys.setrecursionlimit(100000)
class Node:
def __init__(self, ATK, HP, num = 0):
self.atk = ATK
self.hp = HP
self.num = num ##num为攻击次数
self.live = True
n,m = map(int, sys.stdin.readline().split())
bob,alix,pj = 0,0,0
ls_a = list(map(int, sys.stdin.readline().split()))
ls_b = list(map(int, sys.stdin.readline().split()))
for i in range(n):
ls_a[i] = Node(ls_a[i], ls_a[i])
for i in range(m):
ls_b[i] = Node(ls_b[i], ls_b[i])
def find(ls):
"""查找这次哪个随从攻击,返回下标"""
min_ = 0
idx = 0
for i in range(len(ls)):
if ls[i].live:
min_ = ls[i].num
idx = i
break
for i in range(len(ls)):
if not ls[i].live: continue
if ls[i].num == 0 or ls[i].num == min_-1:
return i
return idx
def dfs(first, p, num_a, num_b): ##num_a,num_b 为a,b当前的存活人数
global bob, alix, pj
if first: #a->b
first = not first
idx = find(ls_a)
for i in range(m):
if not ls_b[i].live: continue
ls_a[idx].num = ls_a[idx].num + 1
ls_a[idx].hp -= ls_b[i].atk
ls_b[i].hp -= ls_a[idx].atk
p /= num_b
if ls_a[idx].hp <= 0:
ls_a[idx].live = False
num_a -= 1
if ls_b[i].hp <= 0:
ls_b[i].live = False
num_b -= 1
if num_a == 0 or num_b == 0:
if num_a == 0 and num_b == 0: pj += p
elif num_b == 0 and num_a != 0: alix += p
elif num_a == 0 and num_b != 0: bob += p
if ls_a[idx].live == False:
ls_a[idx].live = True
num_a += 1
if ls_b[i].live == False:
ls_b[i].live = True
num_b += 1
ls_a[idx].hp += ls_b[i].atk
ls_b[i].hp += ls_a[idx].atk
p *= num_b
ls_a[idx].num = ls_a[idx].num - 1
continue
dfs(first, p, num_a, num_b)
if ls_a[idx].live == False:
ls_a[idx].live = True
num_a += 1
if ls_b[i].live == False:
ls_b[i].live = True
num_b += 1
ls_a[idx].hp += ls_b[i].atk
ls_b[i].hp += ls_a[idx].atk
p *= num_b
ls_a[idx].num = ls_a[idx].num - 1
else:
first = not first
idx = find(ls_b)
for i in range(n):
if not ls_a[i].live: continue
ls_b[idx].num = ls_b[idx].num + 1
ls_a[i].hp -= ls_b[idx].atk
ls_b[idx].hp -= ls_a[i].atk
p = p/num_a
if ls_a[i].hp <= 0:
ls_a[i].live = False
num_a -= 1
if ls_b[idx].hp <= 0:
ls_b[idx].live = False
num_b -= 1
if num_a == 0 or num_b == 0:
if num_a == 0 and num_b == 0: pj += p
elif num_b == 0: alix += p
elif num_a == 0: bob += p
if not ls_a[i].live:
ls_a[i].live = True
num_a += 1
if not ls_b[idx].live:
ls_b[idx].live = True
num_b += 1
ls_a[i].hp += ls_b[idx].atk
ls_b[idx].hp += ls_a[i].atk
ls_b[idx].num = ls_b[idx].num-1
p *= num_a
continue
dfs(first, p, num_a, num_b)
if not ls_a[i].live:
ls_a[i].live = True
num_a += 1
if not ls_b[idx].live:
ls_b[idx].live = True
num_b += 1
ls_a[i].hp += ls_b[idx].atk
ls_b[idx].hp += ls_a[i].atk
ls_b[idx].num = ls_b[idx].num - 1
p *= num_a
first = True if n > m else False
if n != m: dfs(first, 1, n, m)
elif n == m:
dfs(False, 0.5, n, m)
dfs(True, 0.5, n, m)
ans = alix+bob+pj
print(f'{alix/ans:.15g}\n{bob/ans:.15g}\n{pj/ans:.15g}')
F、Half Mixed
这题是到构造题,我们可以推出子矩形数量是 n(n+1)/2 * m(m+1)/2,如果子矩形数量是奇数则显 然无解,否则 n(n+1)/2 和 m(m+1)/2 至少有一个是偶数。我们只需要处理一行或一列即可。假设m(m+1)/2 为偶数,则一开始交替放0和1有m个纯子矩阵,我们要让纯子矩阵等于总数的一半即m(m+1)/4,令cnt = m(m+1)/4 - m,为纯子矩阵还差多少,再可以推出每加 k 个相同的数字,纯子矩阵增加 ∑ x (x from 1 to k) = k(k+1)/2,所以只需要贪心的选择最大的k直到cnt为0为止。
上ac代码:
import sys
t = int(sys.stdin.readline())
while t > 0:
t -= 1
n,m = map(int, sys.stdin.readline().split())
num = n * (n+1) * (m+1) * m// 4
if num % 2 != 0:
print("No")
else:
print("Yes")
if n*(n+1)%4 == 0:
cnt = n*(n+1)//4 - n
k,f = 1, 1
ans = [1]
for i in range(n-1):
if cnt >= k:
ans.append(f)
cnt -= k
k += 1
else:
k = 1
f = 0 if f else 1
ans.append(f)
for i in range(n):
for j in range(m):
print(ans[i], end = ' ' if j != m-1 else '\n')
else:
cnt = m*(m+1)//4 - m
k,f = 1, 1
ans = [1]
for i in range(m-1):
if cnt >= k:
ans.append(f)
cnt -= k
k += 1
else:
k = 1
f = 0 if f else 1
ans.append(f)
for i in range(n):
print(*ans)
本文来自博客园,作者:CH-Yu,转载请注明原文链接:https://www.cnblogs.com/chuanhua-blogs/p/18852154