---
# System prepended metadata

title: AtCoder Beginner Contest 171 題解
tags: [Programming Contest]

---

---
tags: Programming Contest
---

# AtCoder Beginner Contest 171 題解

[題目連結](https://atcoder.jp/contests/abc171/tasks)

## 心得

比賽中解出 5 題，排 2053，第三題卡了一段時間。這次前五題偏簡單，一堆人都解出五題，第六題又太難，輸在手速。

## A, B

略

## C. One Quadrillion and One Dalmatians

長度為 1 的字串的上下界是 [1, 26]。
長度為 2 的字串的上下界是 [27, 702]。
長度為 3 的字串的上下界是 [703, 18278]。
...

我觀察到的規律是 **每次的上界是前一次的上界加一再乘上 26**，這個上界指數型成長，所以給定 N，我可以快速地爆開所有的上下界，讓我知道答案是多長的字串。然後再推字母是哪些，即將 (N - 下界) 從 10 進制換成 26 進制。

```python
def solve():
    N = int(input())

    lb, ub = 0, 0
    for n_digit in range(1, 100):
        lb = ub + 1
        ub = (ub + 1) * 26
        if lb <= N <= ub:
            off = N - lb
            res = []
            while off > 0:
                off, r = divmod(off, 26)
                res.append(r)
            while len(res) < n_digit:
                res.append(0)
            res.reverse()
            res = ''.join([chr(ord('a') + x) for x in res])
            return res
    
print(solve())
```

## D. Replacing

$O(QN)$ 肯定不行，自然而然就想到將序列存成**頻率數組**的型式，同時維護目前的序列和。

這題比賽時 TLE 了一次，因為 python `Counter` 的 `pop` 時竟然不是 $O(1)$，最後轉用 `dict` 寫就可以了。

```python
from collections import defaultdict

N = int(input())
A = list(map(int, input().split()))

cnt = defaultdict(int)
for a in A:
    cnt[a] += 1
ttl = sum(A)

Q = int(input())
for _ in range(Q):
    b, c = map(int, input().split())
    
    if b in cnt:
        occ = cnt.pop(b)
        cnt[c] += occ
        ttl = ttl - b * occ + c * occ
    
    print(ttl)
```

## E. Red Scarf

看完題目還再三確認，這種題目一般是放在第二或第三題吧，就 xor 的基本性質：a xor a = 0, a xor 0 = a，這種題目八成是將給定的所有值 xor 在一起後再消掉一些，就如這題。

全部 xor 在一起的值，代表了答案的每項都被算了 N - 1 次在裡面，因為 N - 1 是奇數，也就是說答案的每項都被算了 1 次在裡面（偶數次對消），於是將此值與給定的每項 xor 一下，相同項對消，就能得到答案的各項。

```python
N = int(input())
A = list(map(int, input().split()))

S = 0
for a in A:
    S = S ^ a

for a in A:
    print(S ^ a)
```

## F. Strivore

官方題解看不懂，網路上的也看不懂，直到看到[這篇使用重覆組合](https://kmjp.hatenablog.jp/entry/2020/06/21/1030)，雖然不懂日文，但在 google translate 的幫助下還是弄懂了。

以第一筆範測 `oof` 為例，假設 `K` 次操作後字串變成 `AoBoCfD`，其中 `A, B, C, D` 都是字串（可以是空的），一個重要的觀察是：

1. `A` 不能含有字母 `o`，要不然違反我們的假設，所以 A 只能用 25 種字母來填。
2. 同理 `B` 不能含有 `o`，只能用 25 種字母來填。
3. 同理 `C` 不能含有 `f`，只能用 25 種字母來填。
4. `D` 倒是可以隨便填。

因為 `D` 的性質與 `A, B, C` 不同，我們可以單獨處理 `D`，然後 `A, B, C` 一起做。現在的問題是我們不知道 `A, B, C, D` 的長度，但我們知道 `len(A) + len(B) + len(C) + len(D) = K`。我們枚舉 `D` 的長度，假設 `len(D) = L`，那 `len(A) + len(B) + len(C) = K - L`。`D` 的部份有 26 種字母，`A, B, C` 都有 25 種可以用，所以此時可產出相異字串數

$$
26^L \cdot 25^{K-L} \cdot H^3_{K-L}
$$

其中，$26^L$ 是 `D` 的方法數，$25^{K-L}$ 是 `A, B, C` 的方法數，$H^3_{K-L}$ 是代表 `len(A) + len(B) + len(C) = K - L` 的非負整解的個數。

這題實作上得使用 pypy 或 c++ 才能過，使用 python 會 TLE，以下為 pypy 的 AC Code：

```python
K = int(input())
S = input()
M = int(10 ** 9 + 7)

fact = [1]
for i in range(1, K + len(S) + 10):
    fact.append(fact[-1] * i % M)

finv = [pow(fact[-1], M - 2, M)]
for i in range(K + len(S) + 9, 0, -1):
    finv.append(finv[-1] * i % M)
finv.reverse()

def comb(a, b, m):
    return fact[a] * finv[b] % m * finv[a - b] % m

def hcomb(a, b, m):
    return comb(a + b - 1, a - 1, m)

ans = 0
for l in range(0, K + 1):
    ans += pow(26, l, M) * pow(25, K - l, M) % M * hcomb(len(S), K - l, M) % M
    ans %= M
print(ans)
```

:::success
[< 回到所有題解](https://hackmd.io/@amoshyc/HkWWepaPv/)
:::