c题 又放学辣。
d题 又放学辣。题面:问还留在学校的人数最多的班级的最少可能人数是多少。二分法。
二分法的关键点是如何写check函数。本题使用前缀和和二分查找优化check函数。
时间复杂度:O(n)Log(n)Log(n)
具体代码如下
import bisect
import sys
# sys.stdin = open('./../../input.txt')
I = lambda: int(input())
MI = lambda: map(int, input().split())
LI = lambda: list(map(int, input().split()))
n, m, k = MI()
a = LI()
nums = [0] * m
for x in a:
nums[x - 1] += 1
snums = list(sorted(nums))
pre_sum = [0]
for num in snums:
pre_sum.append(pre_sum[-1] + num)
ans = [0] * m
for i, num in enumerate(nums):
if n - num < k:
ans[i] = -1
continue
l, r = 0, n
while l <= r:
mid = (l + r) // 2
j = bisect.bisect_right(snums, mid)
# print(i)
if num <= mid:
s = pre_sum[-1] - pre_sum[j] - mid * (m - j)
else:
s = pre_sum[-1] - pre_sum[j] - mid * (m - j) - (num - mid)
if s <= k:
ans[i] = mid
r = mid - 1
else:
l = mid + 1
print(' '.join(map(str, ans)))
赛后直播中提到的算法是差分的差分来计算check函数。
时间复杂度:O(n)Log(n)
import sys
# sys.stdin = open('./../../input.txt')
I = lambda: int(input())
MI = lambda: map(int, input().split())
LI = lambda: list(map(int, input().split()))
n, m, k = MI()
a = LI()
c = [0] * m
for x in a:
c[x - 1] += 1
s = [0] * (n + 2)
d = [0] * (n + 2)
for i in range(m):
s[0] += c[i]
d[1] += -1
d[c[i] + 1] += 1
for i in range(1, n + 1):
d[i] += d[i - 1]
s[i] = s[i - 1] + d[i]
ans = [0] * m
for i in range(m):
if n - c[i] < k:
ans[i] = -1
continue
l, r = -1, n
while l + 1 < r:
mid = (l + r) // 2
tot = s[mid]
if tot - (c[i] - min(mid, c[i])) <= k:
r = mid
else:
l = mid
ans[i] = r
print(' '.join(map(str, ans)))
e题:二分图匹配。构建邻接矩阵,直接上板子。
import math
import queue
import sys
def dinic_bfs(capacity, flow, level, source, sink):
# BFS function for Dinic algorithm.
# Check whether sink is reachable only using edges that is not full.
vertices = len(capacity)
q = queue.Queue()
q.put(source)
level[source] = 0
while q.qsize():
front = q.get()
for nxt in range(vertices):
if level[nxt] == -1 and flow[front][nxt] < capacity[front][nxt]:
level[nxt] = level[front] + 1
q.put(nxt)
return level[sink] != -1
def dinic_dfs(capacity, flow, level, idx, sink, work, current_flow = 1 << 63):
# DFS function for Dinic algorithm.
# Finds new flow using edges that is not full.
if idx == sink:
return current_flow
vertices = len(capacity)
while work[idx] < vertices:
nxt = work[idx]
if level[nxt] == level[idx] + 1 and flow[idx][nxt] < capacity[idx][nxt]:
tmp = dinic_dfs(capacity, flow, level, nxt, sink, work, min(current_flow, capacity[idx][nxt] - flow[idx][nxt]))
if tmp > 0:
flow[idx][nxt] += tmp
flow[nxt][idx] -= tmp
return tmp
work[idx] += 1
return 0
def dinic(capacity, source, sink):
# Computes maximum flow from source to sink using Dinic algorithm.
# Time complexity : O(V^2*E)
# V is the number of vertices and E is the number of edges.
vertices = len(capacity)
flow = [[0]*vertices for i in range(vertices)]
ret = 0
while True:
level = [-1 for i in range(vertices)]
work = [0 for i in range(vertices)]
if not dinic_bfs(capacity, flow, level, source, sink):
break
while True:
tmp = dinic_dfs(capacity, flow, level, source, sink, work)
if tmp > 0:
ret += tmp
else:
break
return ret
# sys.stdin = open('./../../input.txt')
I = lambda: int(input())
MI = lambda: map(int, input().split())
LI = lambda: list(map(int, input().split()))
n = I()
a = LI()
b = LI()
N = 2 * n + 2
adj_mtx = [[0 for _ in range(N)] for _ in range(N)]
for i in range(1, n + 1):
adj_mtx[0][i] = 1
for i in range(n + 1, 2 * n + 1):
adj_mtx[i][2 * n + 1] = 1
for i in range(n):
for j in range(n):
if math.gcd(a[i], b[j]) == 1:
adj_mtx[i + 1][j + 1 + n] = 1
rst = dinic(adj_mtx, 0, 2*n+1)
if rst == n:
print('Bob')
else:
print('Alice')
f题 Bob和Alice博弈。
关键点一:直接对a中的每个元素异或k。那么游戏变成出相同的牌则bob赢。
关键点二:贪心。对于bob来说,和a中相同的牌只用存一张,等a出的时候出既可以赢。
import sys
from collections import Counter
# sys.stdin = open('./../../input.txt')
I = lambda: int(input())
MI = lambda: map(int, input().split())
LI = lambda: list(map(int, input().split()))
n, m, k = MI()
a = LI()
b = LI()
a = [x ^ k for x in a]
cnt_a = Counter(a)
cnt_b = Counter(b)
in_b = 0
not_in_b = 0
for k, v in cnt_a.items():
if k in cnt_b:
in_b += v
else:
not_in_b += v
in_a = 0
not_in_a = 0
for k, v in cnt_b.items():
if k in cnt_a:
in_a += 1
not_in_a += v - 1
else:
not_in_a += v
if in_b > 1 and not_in_a + in_a > not_in_b + 1:
print('Bob')
else:
print('Alice')