Rank: 525

🔗 A - 123233 (abc380 A)

tags: 計數(Counting)

題意

給定一個 66 位數的正整數 NN,判斷 NN 是否滿足下列所有條件:

  • NN 的數字中,數字 11 恰好出現 11 次。
  • NN 的數字中,數字 22 恰好出現 22 次。
  • NN 的數字中,數字 33 恰好出現 33 次。

約束條件

  • NN 為一個整數,滿足 100000N999999100000 \le N \le 999999

思路:計數(Counting)

NN 轉換為字串,並統計每個數字出現的次數,最後判斷是否滿足條件即可。

複雜度分析

  • 時間複雜度:O(6)O(6)
  • 空間複雜度:O(10)O(10)
1
2
3
4
5
6
N = input()

cnt = [0] * 10
for ch in N:
cnt[int(ch)] += 1
print("Yes" if (cnt[1] == 1 and cnt[2] == 2 and cnt[3] == 3) else "No")
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'

int main() {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
string s;
cin >> s;
vector<int> cnt(10, 0);
for (auto &ch : s) cnt[ch - '0']++;
cout << ((cnt[1] == 1 && cnt[2] == 2 && cnt[3] == 3) ? "Yes" : "No") << endl;
return 0;
}

🔗 B - Hurdle Parsing (abc380 B)

tags: 分組循環

題意

給定一個字串 SS,其中僅包含 |-,分別輸出每個 | 之間的 - 的長度。

約束條件

  • SS 是一個長度在 33100100 之間(包含 33100100)的字串。
  • SS 中至少包含一個 -

思路:分組循環

我們要計算每段連續的 - 的長度,因此可以透過 分組循環 來處理。

  • 維護一個指標 ii,從 11 開始遍歷字串。
  • 紀錄每一段 - 的起始位置 stst,並向後尋找直到遇到 | 或到達字串的結尾。
  • 計算該段 - 的長度,並將其加入答案陣列。
  • 將指標 ii 往後移動。

此外,由於 SS 一定是由 | 開始,因此可以從索引 11 開始處理,否則需要跳過第一段的長度。

複雜度分析

  • 時間複雜度:O(n)O(n),其中 nn 是字串的長度。
  • 空間複雜度:O(k)O(k),其中 kk 是字串中 | 的數量減 11,也就是答案陣列的長度。在最壞情況下,kk 可能接近 n2\frac{n}{2}
1
2
3
4
5
6
7
8
9
10
11
12
S = input()
n = len(S)

ans = []
i = 1
while i < n:
st = i
while i < n and S[i] != '|':
i += 1
ans.append(i - st)
i += 1
print(*ans)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'

int main() {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
string s;
cin >> s;
int n = s.size();
vector<int> ans;
int i = 1, st;
while (i < n) {
st = i;
while (i < n && s[i] != '|') i++;
ans.push_back(i - st);
i++;
}
for (auto &x : ans) cout << x << ' ';
return 0;
}

🔗 C - Move Segment (abc380 C)

tags: 字串(String) 分組循環

題意

給定一個長度為 NN 的二進位制字串 SS,其由 01 組成。

將連續的 1 視為一個 blocks,將字串 SS 中從開頭數來的第 KK11-block 移動到緊接著第 (K1)(K-1)11-block 之後,並輸出結果字串。

約束條件

  • 1N5×1051 \leq N \leq 5 \times 10^5
  • 2K2 \leq K,且 SS 至少包含 KK11-blocks。

思路:分組循環

這題和前一題類似,需要找到每一個連續的 1 組成的 blocks,並將第 KK 個 block 移動到第 (K1)(K-1) 個 block 之後。

因此可以透過 分組循環 來找到每一個 block 的起始和結束位置 [l,r][l, r],並將第 KK 個 block 移動到第 (K1)(K-1) 個 block 之後。

令第 KK 個 block 的起始和結束位置為 [l,r][l, r],第 (K1)(K-1) 個 block 的結束位置為 rprevr_{prev},則需要交換的區間分別為 [l,r][l, r][rprev+1,l1][r_{prev} + 1, l - 1],直接交換即可。

複雜度分析

  • 時間複雜度:O(N)O(N),其中 NN 是字串的長度。
  • 空間複雜度:O(N)O(N)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
N, K = map(int, input().split())
S = input()

blocks = []
i = 0
while i < N:
if S[i] == '1':
st = i
while i + 1 < N and S[i + 1] == '1':
i += 1
blocks.append((st, i))
i += 1

r_prev = blocks[K - 2][1]
l, r = blocks[K - 1]
print(S[:r_prev+1] + S[l:r+1] + S[r_prev+1:l] + S[r+1:])
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'

int main() {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
int n, k;
cin >> n >> k;
string s;
cin >> s;
vector<pair<int, int>> blocks;
for (int i = 0, st; i < n; i++) {
if (s[i] == '1') {
st = i;
while (i < n && s[i] == '1') i++;
blocks.push_back({st, i - 1});
}
}
int r_prev = blocks[k - 2].second;
int l = blocks[k - 1].first, r = blocks[k - 1].second;
string ans = "";
ans += s.substr(0, r_prev + 1);
ans += s.substr(l, r + 1 - l);
ans += s.substr(r_prev + 1, l - r_prev - 1);
ans += s.substr(r + 1);
cout << ans << endl;
return 0;
}

🔗 D - Strange Mirroring (abc380 D)

tags: 迭代(Iteration) 遞迴(Recursion)

題意

給定一個由大寫和小寫英文字母組成的字串 SS,對 SS 執行以下操作 1010010^{100} 次:

  • 構建一個字串 TT,其內容為 SS 中的大寫字母變成小寫,小寫字母變成大寫後的結果。
  • TT 附加到 SS 後面。

回答 QQ 個查詢。第 ii 個查詢如下:

  • 找出所有操作完成後,從 SS 開始的第 KiK_i 個字符。

約束條件

  • S2×105|S| \leq 2 \times 10^5
  • 1Q2×1051 \le Q \le 2 \times 10^5
  • 1Ki10181 \le K_i \le 10^{18}

思路

由於操作次數達到 1010010^{100},直接模擬這麼大次數的操作顯然不可行,因此需要找到一種更高效的方式來確定查詢位置的字符。

首先,觀察每次操作的規則:將目前的字串 SS 中的大寫字母變成小寫,小寫字母變成大寫後,附加到原字串的末尾。這意味著每進行一次操作,字串的長度會翻倍。因此,在 mm 次操作後,字串的長度將達到 n×2mn \times 2^m。而我們可以利用這個性質來確定查詢位置 KiK_i 所在的字串是位於第 mm 次操作後的原始部分 SS 或翻轉部分 TT

舉例來說,令 0 表示未翻轉,1 表示翻轉。則對於字串 aB 而言,前 44 次操作如下:

  1. 00
  2. 0011
  3. 00111100
  4. 0011110011000011
    對於 K=15K = 15 而言,他上次是由 K=7K = 7 翻轉而來;再上次是 K=3K = 3,再再上次是 K=1K = 1,這已經在原始字串中,因此不再翻轉。故 K=15K = 15 相對 K=1K = 1 翻轉了 33 次。

因此,可以維護長度 [n,2n,4n,8n,16n,...][n, 2n, 4n, 8n, 16n, ...],由後往前檢查 KiK_i 所在的位置是否屬於原始字串 SS 或是其翻轉後的部分 TT。如果 KiK_i 落在翻轉後的部分 TT,我們將其映射回對應的原始位置,並記錄翻轉的次數 cntcnt,直到找到原始字串中的字符為止。

最終,根據翻轉的總次數 cntcnt 的奇偶性來決定是否需要對該字符進行大小寫反轉即可。

複雜度分析

  • 時間複雜度:O(QlogM)O(Q \log M),其中 QQ 是查詢的數量,M=max(K)M = \max(K) 是查詢位置的最大值。
  • 空間複雜度:O(logM)O(\log M)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
S = input()
Q = int(input())
queries = list(map(int, input().split()))

n = len(S)
ln = [n]
MAX_LN = 1e18
while ln[-1] <= MAX_LN:
ln.append(ln[-1] * 2)
m = len(ln)

ans = []
for k in queries:
cnt = 0
for i in range(m - 1, 0, -1):
if k > ln[i - 1]:
k = k - ln[i - 1]
cnt += 1
ch = S[k - 1]
if cnt & 1:
ch = ch.upper() if ch.islower() else ch.lower()
ans.append(ch)
print(*ans)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
const LL MAX_LN = 1e18;
#define endl '\n'

int main() {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
string s; cin >> s;
int n = s.size();
int q; cin >> q;
vector<LL> ln = {n};
while (ln.back() <= MAX_LN) ln.push_back(ln.back() * 2);
reverse(ln.begin(), ln.end());
while (q--) {
LL k; cin >> k;
int cnt = 0;
for (auto &x : ln) {
if (k > x) {
k -= x;
cnt++;
}
}
char ch = s[k - 1];
if (cnt & 1) ch = islower(ch) ? toupper(ch) : tolower(ch);
cout << ch << " ";
}
cout << endl;
return 0;
}

🔗 E - 1D Bucket Tool (abc380 E)

tags: 併查集(Disjoint Set)

題意

從左到右有 NN 個兩兩相鄰且連續排列的格子,編號為 11NN。最初,第 ii 個格子的顏色為 ii

處理 QQ 個查詢:

  • 1 x c: 將 xx 號格子及其相鄰的、顏色和 xx 號格子相同的格子塗上顏色 cc
  • 2 c: 輸出被塗上顏色 cc 的單元格數量。

約束條件

  • 1N5×1051 \leq N \leq 5 \times 10^5
  • 1Q2×1051 \leq Q \leq 2 \times 10^5

思路:區間併查集(Disjoint Set)

我們可以將顏色相同的且相鄰的格子視為一個連續區間,並且用 併查集(Disjoint Set) 來維護這些區間。除了維護每個節點所屬的區間編號 papa 、以及每個區間的大小 szsz 外,由於需要處理操作 2,還需要額外維護每個區間的顏色 colorcolor 以及每個顏色的格子數量 cntcnt

由於在操作 1 中,我們需要將某個格子及其相鄰的、顏色和該格子相同的格子塗上顏色 cc,而在對該區間塗色後,又可能需要和相鄰的區間合併,因此需要檢查是否需要合併左側和右側區間。為此,我們可以在 union 操作時改成依照每個區間的左端點合併,即該區間的左端點為 fx=find(x)f_x = \text{find}(x),由於維護的是一個連續區間,因此也可以得右端點為 fx+sz[fx]1f_x + sz[f_x] - 1。故合併時只需要檢查 left=fx1left = f_x - 1right=fx+sz[fx]right = f_x + sz[f_x] 所屬的區間的顏色是否和新顏色 cc 相同即可,如果相同則需要合併。

需要注意的是,合併後的區間左端點 fxf_x 可能會改變,因此需要先合併 rightright 再合併 leftleft,或是需要重新計算 fxf_x 的值。

具體步驟如下:

  • 對於操作 1 x c,我們首先找到格子 xx 所在的區塊,檢查其顏色是否已經是 cc。如果不是,則更新顏色,並調整 cntcnt 陣列:否則直接跳過即可。
    • 令原本的顏色為 cur_ccur\_c,更新後的顏色為 cc。則 cnt[cur_c]cnt[cur\_c] 減少了 xx 所在區間的大小 sz[fx]sz[f_x]cnt[c]cnt[c] 增加了 xx 所在區間的大小 sz[fx]sz[f_x]
    • 更新顏色後,我們檢查該區塊的左側和右側是否有相鄰且顏色相同的區塊,如果有,則將它們合併成一個更大的區塊。
  • 對於操作 2 c ,直接輸出 cnt[c]cnt[c] 即可。

複雜度分析

  • 時間複雜度:O(Qα(N))O(Q \cdot \alpha(N))
  • 空間複雜度:O(N)O(N)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
class UnionFind:
def __init__(self, n):
self.pa = list(range(n))
self.sz = [1] * (n)

def find(self, x):
if self.pa[x] != x:
self.pa[x] = self.find(self.pa[x])
return self.pa[x]

def union(self, x, y):
fx, fy = self.find(x), self.find(y)
if fx == fy:
return fx
if fx > fy: # 按照左端點合併
fx, fy = fy, fx
self.pa[fy] = fx
self.sz[fx] += self.sz[fy]
return fx

N, Q = map(int, input().split())
queries = [list(map(int, input().split())) for _ in range(Q)]

uf = UnionFind(N + 1)
color = [i for i in range(N + 1)] # color[i] 表示 i 所在的 component 的顏色
cnt = [1] * (N + 1) # cnt[i] 表示顏色 i 的數量

for q in queries:
op, *args = q
if op == 1:
x, c = args
fx = uf.find(x)
cur_c = color[fx]
if cur_c == c:
continue
# 需要修改顏色
left, right = fx - 1, fx + uf.sz[fx] # 左側區間和右側區間
cnt[cur_c] -= uf.sz[fx] # 原本顏色的數量減少這個 component 的大小
cnt[c] += uf.sz[fx] # 新顏色的數量增加這個 component 的大小
color[fx] = c # 更新這個 component 的顏色
if right <= N: # 檢查是否需要合併右側區間
fr = uf.find(right)
if color[fr] == c: # 右側區間的顏色相同
uf.union(fx, fr)
if left >= 1: # 檢查是否需要合併左側區間
fl = uf.find(left)
if color[fl] == c: # 左側區間的顏色相同
uf.union(fx, fl)
else:
c = args[0]
print(cnt[c])
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'

class UnionFind {
public:
vector<int> pa, sz;
UnionFind(int n) : pa(n), sz(n, 1) {
iota(pa.begin(), pa.end(), 0);
}
int find(int x) {
if (pa[x] != x) pa[x] = find(pa[x]);
return pa[x];
}
void merge(int x, int y) {
int fx = find(x), fy = find(y);
if (fx == fy) return;
if (fx > fy) swap(fx, fy); // 按照左端點合併
pa[fy] = fx;
sz[fx] += sz[fy];
}
};

int main() {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
int n, q; cin >> n >> q;
int op, x, c;
UnionFind uf(n + 1);
vector<int> color(n + 1), cnt(n + 1);
for (int i = 1; i <= n; i++) color[i] = i, cnt[i] = 1;
while (q--) {
cin >> op;
if (op == 1) {
cin >> x >> c;
int fx = uf.find(x);
if (color[fx] == c) continue;
// 需要修改顏色
int left = fx - 1, right = fx + uf.sz[fx]; // 左側區間和右側區間
cnt[color[fx]] -= uf.sz[fx]; // 原本顏色的數量減少這個 component 的大小
cnt[c] += uf.sz[fx]; // 新顏色的數量增加這個 component 的大小
color[fx] = c; // 更新這個 component 的顏色
if (right <= n) { // 檢查是否需要合併右側區間
int fr = uf.find(right);
if (color[fr] == c) { // 右側區間的顏色相同
uf.merge(fx, fr);
}
}
if (left >= 1) { // 檢查是否需要合併左側區間
int fl = uf.find(left);
if (color[fl] == c) { // 左側區間的顏色相同
uf.merge(fx, fl);
}
}
} else {
cin >> c;
cout << cnt[c] << endl;
}
}
return 0;
}

🔗 F - Exchange Game (abc380 F)

tags: 博弈論(Game Theory) 記憶化搜尋(Memoization) 狀態壓縮DP(Bitmask DP)

題意

有兩位玩家,他們將使用寫有數字的卡牌進行遊戲。最初,玩家 A 的手上有 NN 張卡牌,數字分別為 A1,,ANA_1, \ldots, A_N;玩家 B 的手上有 MM 張卡牌,數字分別為 B1,,BMB_1, \ldots, B_M;桌上有 LL 張卡牌,數字分別為 C1,,CLC_1, \ldots, C_L

在整個遊戲過程中,玩家 A 和玩家 B 都知道所有卡牌上的數字,包括對方手中的卡牌。

遊戲由玩家 A 先開始,他們輪流執行以下動作:

  • 從自己的手牌中選擇一張卡牌放到桌上。然後,如果桌上有卡牌的數字小於他剛放下的卡牌的數字,他可以從桌上取走其中一張這樣的卡牌回到自己的手中。

最先無法進行動作的玩家輸,另一個玩家贏。如果 雙方都以最優策略進行遊戲 ,判斷誰會獲勝。

約束條件

Constraints

  • 1N,M,L1 \leq N, M, L
  • N+M+L12N + M + L \leq 12

思路:博弈論(Game Theory) + 狀態壓縮DP(Bitmask DP) + 記憶化搜尋(Memoization)

由於卡牌的數量 N+M+L12N + M + L \leq 12,因此可以考慮狀態壓縮DP,維護兩個玩家的目前手牌以及輪到誰的回合三個狀態,其中手牌的狀態可以用一個整數的二進位表示。

在輪到某玩家時,可以枚舉可能的選擇,這包含兩個部分:

  1. 打出手中的一張牌
  2. 不回收任何牌、或是回收桌上比剛剛打出的牌小的牌。

由於雙方都以最優策略進行遊戲,因此如果任何一種選擇使得對方必輸,則自己必贏。

實現時,使用 記憶化搜尋(Memoization) 來實現即可。令 f(a,b,flag)f(a, b, flag) 表示當前輪到 flagflag 玩家出牌,aabb 分別是兩個玩家的手牌,返回該玩家是否能獲勝。

具體步驟如下:

  1. 使用 Bitmask 來表示每張卡牌的所在位置:
    • 玩家 A 的手牌:用一個整數 aa 的二進位表示,每一位代表一張卡牌是否在玩家 A 的手中。
    • 玩家 B 的手牌:用另一個整數 bb 的二進位表示,每一位代表一張卡牌是否在玩家 B 的手中。
    • 桌面上的卡牌:通過 aabb 的補集  (ab)~(a | b) 來表示,即不在任何一位玩家手中的卡牌即在桌面上。不過由於有效的卡牌編號為 0,,N+M+L10, \ldots, N + M + L - 1,因此需要再對 mask=(1<<(N+M+L))1mask = (1 << (N + M + L)) - 1 取交集。
  2. 在每一個遊戲狀態,需要考慮當前玩家可以執行的行動:
    1. 打出手上的牌:遍歷當前玩家手中的所有卡牌,選擇其中一張出到桌面上。若當前玩家無法出牌,則該玩家輸,對方獲勝。
    2. 不回收任何牌、或是回收桌上比剛剛打出的牌小的牌
      • 不回收任何牌:僅將選中的牌放到桌面上,轉換到下一位玩家的回合。
      • 回收一張較小的牌:如果桌面上存在比剛出牌小的卡牌,可以選擇其中一張回收到自己的手中,然後轉換到下一位玩家的回合。
  3. 在這些行動中,如果存在一種行動使得對方必輸,則自己必贏;否則,若所有行動都使得對方必贏,則自己必輸。

複雜度分析

  • 時間複雜度:O((N+M+L)23N+M+L)O((N+M+L)^2 \cdot 3^{N+M+L})
    • 每張卡牌有三種可能的狀態,因此狀態數量最多有 3N+M+L3^{N+M+L}
    • 每種狀態需要 O(N+M+L2)O({N+M+L}^2) 的時間枚舉可能的選擇
  • 空間複雜度:O(3N+M+L)O(3^{N+M+L})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import sys
from functools import cache
sys.setrecursionlimit(10**6)

N, M, L = map(int, input().split())
A = list(map(int, input().split()))
B = list(map(int, input().split()))
C = list(map(int, input().split()))

cards = A + B + C

mask = (1 << (N + M + L)) - 1
a = 0
for i in range(N):
a |= (1 << i)
b = 0
for i in range(N, N + M):
b |= (1 << i)

# f(a, b, flag) 表示當前輪到某玩家出牌,a 和 b 分別是兩個玩家的手牌,返回某玩家是否能贏
@cache
def f(a, b, flag):
table = (~(a | b)) & mask # 桌面上的牌是兩個玩家手牌以外的牌

cur = a if flag else b

# 當前玩家沒有牌可打就輸了
if cur == 0:
return False

# 枚舉要打出的牌
for i, x in enumerate(cards):
if (cur >> i) & 1 == 0:
continue

if flag:
n_a = a & ~(1 << i)
n_b = b
else:
n_a = a
n_b = b & ~(1 << i)

n_table = table | (1 << i) # 桌面上的牌加上剛剛打出的牌

if not f(n_a, n_b, flag ^ 1): # 不回收牌
return True

for j, y in enumerate(cards):
if ((n_table >> j) & 1) and (y < x): # 這張牌在桌面上,且比剛剛打出的牌小,可以回收
if flag:
if not f(n_a | (1 << j), n_b, flag ^ 1):
return True
else:
if not f(n_a, n_b | (1 << j), flag ^ 1):
return True
return False

print("Takahashi" if f(a, b, 1) else "Aoki")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'

int main() {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
int n, m, l;
cin >> n >> m >> l;
vector<int> cards(n + m + l);
for (int i = 0; i < n + m + l; i++) cin >> cards[i];
int mask = (1 << (n + m + l)) - 1;
int a = 0, b = 0;
for (int i = 0; i < n; i++) a |= (1 << i);
for (int i = n; i < n + m; i++) b |= (1 << i);

unordered_map<int, int> memo; // Memoization
auto f = [&](auto &&f, int a, int b, bool flag) -> bool {
int key = a << (n + m + l + 1) | b << 1 | flag;
if (memo.count(key)) return memo[key];

int cur = flag ? a : b; // 當前輪到某玩家出牌
if (cur == 0) return false; // 當前玩家沒有牌可打就輸了
int table = ~(a | b) & mask; // 桌面上的牌是兩個玩家手牌以外的牌

int n_a, n_b, n_table;
for (int i = 0; i < n + m + l; i++) { // 枚舉要打出的牌
if (!((cur >> i) & 1)) continue; // 如果當前玩家沒有這張牌則跳過

if (flag) {
n_a = a & ~(1 << i);
n_b = b;
} else {
n_a = a;
n_b = b & ~(1 << i);
}

n_table = table | (1 << i); // 桌面上的牌加上剛剛打出的牌
if (!f(f, n_a, n_b, flag ^ 1)) return memo[key] = true; // 不回收牌
for (int j = 0; j < n + m + l; j++) {
if (((n_table >> j) & 1) && (cards[j] < cards[i])) { // 這張牌在桌面上,且比剛剛打出的牌小,可以回收
if (flag) {
if (!f(f, n_a | (1 << j), n_b, flag ^ 1)) return memo[key] = true;
} else {
if (!f(f, n_a, n_b | (1 << j), flag ^ 1)) return memo[key] = true;
}
}
}
}
return memo[key] = false;
};
cout << (f(f, a, b, 1) ? "Takahashi" : "Aoki") << endl;

return 0;
}

寫在最後

PROMPT

Kamisato Ayaka, a serene and dreamy image of Kamisato Ayaka, an anime girl with long flowing white hair, gracefully reclines on a bed adorned with crisp white sheets. She wears a stylish school uniform featuring a fitted white shirt, a deep blue sailor collar, and a pleated blue skirt, accented by a vibrant blue bow around her neck and a striking red bow in her hair. Her large blue eyes gaze softly at the viewer, sparkling with warmth, while a gentle blush graces her cheeks, enhancing her youthful charm.

The room is awash in soft blue and white tones, but with increased contrast to highlight the details, as sunlight streams through a nearby window on the right, casting a warm, inviting glow across the scene. Plush blue pillows are arranged behind her, providing comfort, and a book with scattered petals lies open beside her, suggesting a moment of leisure.

Ayaka’s posture is relaxed yet natural, with one arm resting comfortably behind her head while the other gently cradles a small, delicate flower. Her serene expression is complemented by a peaceful atmosphere, heightened by the presence of a smartphone and a stylish school bag nearby. The scene is completed with a touch of elegance from her intricate hair ornament and choker, creating a harmonious and vibrant blend of elements that draws the viewer into her tranquil world.