牛客小白月赛80

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')
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值