课堂计划
P10135 [USACO24JAN] Potion Farming S
每个叶子恰好走一次,若叶子个数为 $v$,则只需考虑前 $v$ 次遍历。若一个子树中有 $n$ 次药水出现,$m$ 个叶子,则其对答案的贡献为 $min(n, m)$
N = int(1e5 + 19)
p = [0] * N
cnt = [0] * N
dep = [0] * N
tot = 0
mx = 0
f = [0] * N
fa = [0] * N
g = [[] for _ in range(N)]
depid = [[] for _ in range(N)]
def dfs(node, parent):
global mx, tot
dep[node] = dep[parent] + 1
fa[node] = parent
mx = max(dep[node], mx)
depid[dep[node]].append(node)
flag = False
for neighbor in g[node]:
if neighbor != parent:
dfs(neighbor, node)
flag = True
if not flag:
tot += 1
f[node] += 1
def read():
return int(input().strip())
def write(value, end_char):
print(value, end=end_char)
n = read()
for i in range(1, n + 1):
p[i] = read()
for _ in range(1, n):
a, b = read(), read()
g[a].append(b)
g[b].append(a)
dfs(1, 1)
for i in range(1, tot + 1):
cnt[p[i]] += 1
ans = 0
while mx:
for i in depid[mx]:
if f[i]:
if cnt[i] <= f[i]:
f[i] -= cnt[i]
ans += cnt[i]
else:
ans += f[i]
f[i] = 0
f[fa[i]] += f[i]
mx -= 1
write(ans, '\n')
P5197 [USACO19JAN] Grass Planting S
一个点的相邻的点都不能是同一颜色,如果算上自己有 $n$ 个颜色,那就至少要 $n$ 个颜色。
定义每个点的度为 d[i]
,取 d[i] + 1
的最大值就是答案吗?答案是肯定。设最大值为 $t$,则先随便涂一个点 $i$ 的相邻点,以它为根继续考虑孩子颜色,发现对于每个孩子来说只有 $2$ 个颜色被确定了,从剩下 $t - 2$ 个颜色中任意选一些不同的颜色来涂孩子,以此递归就可以。
x = 0
y = 0
ans = 0
n = 0
deg = [0] * 100007
n = int(input())
for i in range(1, n):
x, y = map(int, input().split())
deg[x] += 1 # 统计度数
deg[y] += 1
if deg[x] > ans:
ans = deg[x] + 1
if deg[y] > ans:
ans = deg[y] + 1
print(ans + 1)
P7148 [USACO20DEC] Cowntagion S
首先,对于每一个节点,如果它的感染者数目已经超过了儿子数,则进行的一定是儿子个数次 (2) 操作。
反之,如果在还没有足够的感染者个数的情况下就开始分,显然是不优的。
所以对于每一个节点都进行贪心:
- 如果还不够分,就执行若干次 (1) 操作,直到够分了为止。
- 如果已经够分了,就花若干天,每天执行一次 (2) 操作直到所有儿子都有感染者为止。
很容易证明这是最优的。
于是我们记录每一个节点的儿子个数,记为 cson[u]cson[u],每次 dfsdfs 到一个点,我们就先计算 logcson[u]+1logcson[u]+1,表示自增至足够感染者的天数(注意不是 ceil),然后进行分发,即花 cson[u]cson[u] 天给所有儿子都发一个感染者,最后注意根节点本身就有一只感染者,处理一下即可。