一个“纯职业小组”定义为由 3 名同职业的士兵组成的队伍。
判断是否有解
遍历所有职业计算出最大队伍数量。
res = 0
for i in range(n):
res += b[i] // 3
if res < k:
print(-1)
continue
有解
假设有:
职业 | a | b | c | d |
---|---|---|---|---|
数量 | 1 | 2 | 3 | 4 |
假设 k=1,如果想要多选一些人,那就是不希望太快凑出队伍,可以先选 1 个 a,2 个 b,2 个 c,2 个 d(选两个是因为如果三个,就凑成一支队伍了)。
这时:
职业 | a | b | c | d |
---|---|---|---|---|
数量 | 0 | 0 | 1 | 2 |
已选 7 人,接下来再选一个 c 或者 d,即可凑成一支队伍。
根据上述分析,以及贪心思想,我们可以先将所有队伍取出 2 个人,若队伍为 1 人则取 1 人,此时不构成一支队伍。
好的,接下来我们要如何做?
先选出所有的 <3 的人头,这些都是白送的 /doge。
- 如果 k=1,那就只能再选一个人,就成一个队伍了。
- 如果 k>1,
- 如果有一个剩余 ≤3 个人的职业,那就先选 1 个构成一支队伍,然后可以白嫖两个 /doge,因为再选两个,是不会构成一支队伍的,但是可以导致我们的答案更优。
- 如果有一个剩余 ≤2 个人的职业,那就先选 1 个构成一支队伍,然后可以白嫖一个,因为再选一个,是不会构成一支队伍的,但是可以导致我们的答案更优。
- 如果有一个剩余 ≤1 个人的职业,那就选 1 个构成一支队伍。
很显然,根据贪心的策略,有 3 选 3,无 3 选 2,无 2 选 1。
那么如何处理 k=1 的情况,我们可以直接将读入的 k 直接 k−=1,res+=1,因为,如果有解的情况下,我们刚开始白嫖的时候,一定会白嫖到最少一种职业有 2 个人,那么再选一个就会导致直接构成一支队伍,但是 res 只有 +1,和前面的贪心分析不合,故可以特殊处理。
T = int(input())
for _ in range(T):
n, k = map(int, input().split())
h = {}
for i in range(n):
a, b = map(int, input().split())
if a not in h:
h[a] = 0
h[a] += b
b = []
for x in h:
b.append(h[x])
n = len(b)
cnt = 0
res = 0
for i in range(n):
cnt += b[i] // 3
u = min(b[i], 2)
b[i] -= u
res += u
if cnt < k:
print(-1)
continue
c1, c2, c3 = 0, 0, 0
for x in b:
c3 += x // 3
x %= 3
if x == 1:
c1 += 1
elif x == 2:
c2 += 1
k -= 1
res += 1
v = min(k, c3)
k -= v
c3 -= v
res += v * 3
v = min(k, c2)
k -= v
c2 -= v
res += v * 2
v = min(k, c1)
k -= v
c1 -= v
res += v * 1
print(res)