AtCoderBeginnerContest459

2026/05/23

A - Hell, World!

func solve(in *FastScanner, out *bufio.Writer) {

	s := "HelloWorld"
	n := in.NextInt()
	for idx, val := range s {
		if idx == n-1 {
			continue
		}
		fmt.Fprintf(out, "%c", val)
	}
}

B - 459

func solve(in *FastScanner, out *bufio.Writer) {
	n := in.NextInt()
	for range n {
		s := in.Next()
		if s[0] <= 'o' {
			t := (s[0]-'a')/3 + 2
			fmt.Fprint(out, t)
		} else if s[0] >= 'p' && s[0] <= 's' {
			fmt.Fprint(out, 7)
		} else if s[0] >= 't' && s[0] <= 'v' {
			fmt.Fprint(out, 8)
		} else {
			fmt.Fprint(out, 9)
		}
	}
}

C - Drop Blocks

cnt[i] 表示第 i 格放了多少块

num[i] 表示有多少位置的数量 $\ge i$

mn 表示 发生了多少次全局 -1

注意判断 $y+mn < q$

func solve(in *FastScanner, out *bufio.Writer) {
	n, q := in.NextInt(), in.NextInt()
	cnt := make([]int, n+1)
	num := make([]int, q+1)
	mn := 0
	for range q {
		opt, val := in.NextInt(), in.NextInt()
		if opt == 1 {
			cnt[val]++
			num[cnt[val]]++
			if num[cnt[val]] == n {
				mn = cnt[val]
			}
		} else {
			if val+mn > q {
				fmt.Fprintln(out, 0)
			} else {
				fmt.Fprintln(out, num[val+mn])
			}
		}
	}
}

D - Adjacent Distinct String

鸽巢原理的结论

最多的数量不超过 $\left\lceil \frac{n}{2} \right\rceil$ 即可

相邻不相等,那数量最多的字符一定是放在 1,3,5... ,如果这个数量大于 $\left\lceil \frac{n}{2} \right\rceil$,那一定有一个放在了偶数位置

放置方案就是先把最多的放奇数位,其他数字继续填奇数位(如果还有位置),剩下的随便放即可

比如:

1 2 1 2 1 4 3 4 3

func solve(in *FastScanner, out *bufio.Writer) {
	n := in.NextInt()
	var cnt [26]int
	for range n {
		for i := range cnt {
			cnt[i] = 0
		}

		s := in.Next()
		cho := 0
		for _, val := range s {
			cnt[int32(val-'a')]++
			if cnt[int32(val-'a')] > cnt[cho] {
				cho = int(val - 'a')
			}
		}
		if cnt[cho] > (len(s)+1)/2 {
			fmt.Fprintln(out, "No")
		} else {
			fmt.Fprintln(out, "Yes")
			ans := make([]byte, len(s))

			p := 0
			idx := 0
			for ; p < len(s) && cnt[cho] > 0; p += 2 {
				ans[p] = byte('a' + cho)
				cnt[cho]--
			}

			for ; p < len(s); p += 2 {
				for cnt[idx] == 0 {
					idx++
				}
				ans[p] = byte('a' + idx)
				cnt[idx]--
			}
			p = 1
			for ; p < len(s); p += 2 {
				for cnt[idx] == 0 {
					idx++
				}
				ans[p] = byte('a' + idx)
				cnt[idx]--
			}
			fmt.Fprintln(out, string(ans))
		}
	}
}

E - Select from Subtrees

以样例1为例子

$f_i$ 表示以 $i$ 为根的子树的方案数

先考虑叶子的方案数:

$f_4=\binom{C_4}{D_4},f_5=\binom{C_5}{D_5}$

怎么从叶子转移到父节点,比如3号点

$f_3=f_4 * f_5 *\binom{剩余可选节点}{D_3}$

剩余可选点可以在 dp 的时候顺便算出来

注意 $C_i$ 很大,算组合数时需要直接用$\binom{n}{m}=\frac{n*(n-1)(n-m+1)}{m!}$

$m!$ 可以预处理

var fac [1_000_100]int64

// 处理阶乘的逆元
fac[1] = 1
for i := 2; i <= 1_000_000; i++ {
  fac[i] = fac[i-1] * int64(i) % mod
}
fac[1_000_000] = powMod(fac[1_000_000], mod-2, mod)
for i := 1_000_000 - 1; i >= 1; i-- {
  fac[i] = fac[i+1] * int64(i+1) % mod
}

const mod = 998_244_353

func solve(in *FastScanner, out *bufio.Writer) {
	n := in.NextInt()
	e := make([][]int, n+1)
	c := make([]int64, n+1)
	d := make([]int64, n+1)
	f := make([]int64, n+1)
	for i := 2; i <= n; i++ {
		x := in.NextInt()
		e[x] = append(e[x], i)
	}
	for i := 1; i <= n; i++ {
		c[i] = in.NextInt64()
	}
	for i := 1; i <= n; i++ {
		d[i] = in.NextInt64()
	}

	C := func(n, m int64) int64 {
		if m > n {
			return int64(0)
		}
		ans := int64(1)
		for i := n; i >= n-m+1; i-- {
			ans = ans * int64(i) % mod
		}
		ans = ans * fac[m] % mod
		return ans
	}

	var dfs func(int)
	dfs = func(x int) {
		if len(e[x]) == 0 {
			f[x] = C(c[x], int64(d[x]))
			return
		}
		totnum := c[x]
		totsub := int64(0)
		for _, to := range e[x] {
			dfs(to)
			totsub += d[to]
			totnum = (totnum + c[to]) % mod
		}
		f[x] = 1
		for _, to := range e[x] {
			f[x] = f[x] * f[to] % mod
		}
		f[x] = f[x] * C((totnum-totsub+mod)%mod, d[x]) % mod
		c[x] = totnum
		d[x] = d[x] + totsub
	}
	dfs(1)

	fmt.Fprintln(out, f[1])

}

F - -1, +1

题目要求 $A_i < A_{i+1}$ ,可以转化为 $ B_i =A_i -i$

这样等效为 $ B_i \le B_{i+1}$

令操作后的 $B$ 数组为 $C$ ,它们的前缀和分别为$ Sb,Sc$

每对 $i$ 操作时,$B_i-1,B_{i+1}+1$,可以转化为 $B_i$ 的前缀和 $(Sb_i)$ 的和 $-1$

那么答案就是 $\sum_{i=1}^n Sb_i-Sc_i $,$Sb_i$ 是固定值,所以要让 $\sum_{i=1}^n Sc_i $ 尽可能大

现在的问题转化为:

保证 $ B_i \le B_{i+1}$ 的前提下,让 $\sum_{i=1}^n Sc_i $ 尽可能大

前缀和的性质决定了,一定是前面的越大越好,再结合 $ B_i \le B_{i+1}$,就得到了最优方案一定是尽量平均,也就是 $x,x,…,x+1,x+1$ 这样的形式

把每个 $B_i$ 看成一个区间,会有以下情况

$B_i \le B_{i+1}$ 满足性质

$B_i > B_{i+1}$ 需要尽量平均,也就是平均为一个新区间 $now: [x,x+1/x] $

下一个区间$ B_{i+2} $ 就要和 $now[1]$ 重复上面的比较

这个冲突合并可以用单调栈实现

func floorDiv(a, b int64) int64 {
	q := a / b
	r := a % b
	if r != 0 && a < 0 {
		q--
	}
	return q
}

func ceilDiv(a, b int64) int64 {
	q := a / b
	r := a % b
	if r != 0 && a > 0 {
		q++
	}
	return q
}
func solve(in *FastScanner, out *bufio.Writer) {
	n := in.NextInt()
	a := make([]int64, n+1)
	b := make([]int64, n+1)
	for i := 1; i <= n; i++ {
		a[i] = in.NextInt64() - int64(i)
	}

	cmp := func(a, b Pair[int64]) bool {
		return upperBySign(a.x, a.y) > lowerBySign(b.x, b.y)
	}
	// sum,len
	q := []Pair[int64]{}
	for i := 1; i <= n; i++ {
		now := Pair[int64]{a[i], 1}
		if len(q) == 0 || !cmp(q[len(q)-1], now) {
			q = append(q, now)
			continue
		}
		for len(q) != 0 && cmp(q[len(q)-1], now) {
			now = Pair[int64]{q[len(q)-1].x + now.x, q[len(q)-1].y + now.y}
			q = q[:len(q)-1]
		}
		q = append(q, now)
	}

	idx := int64(1)
	for _, val := range q {
		lo := floorDiv(val.x, val.y)
		hi := ceilDiv(val.x, val.y)
		r := val.x - lo*val.y

		for i := int64(0); i < val.y; i++ {
			if i < val.y-r {
				b[idx+i] = lo
			} else {
				b[idx+i] = hi
			}
		}
		idx += val.y
	}

	ans := int64(0)
	for i := 1; i <= n; i++ {
		a[i] = a[i-1] + a[i]
		b[i] = b[i-1] + b[i]
		ans += a[i] - b[i]
	}
	fmt.Fprintln(out, ans)
}