"""# ### 谜题描述 Let F_k denote the k-th term of Fibonacci sequence, defined as below: * F_0 = F_1 = 1 * for any integer n ≥ 0, F_{n+2} = F_{n+1} + F_n You are given a tree with n vertices. Recall that a tree is a connected undirected graph without cycles. We call a tree a Fib-tree, if its number of vertices equals F_k for some k, and at least one of the following conditions holds: * The tree consists of only 1 vertex; * You can divide it into two Fib-trees by removing some edge of the tree. Determine whether the given tree is a Fib-tree or not. Input The first line of the input contains a single integer n (1 ≤ n ≤ 2 ⋅ 10^5) — the number of vertices in the tree. Then n-1 lines follow, each of which contains two integers u and v (1≤ u,v ≤ n, u ≠ v), representing an edge between vertices u and v. It's guaranteed that given edges form a tree. Output Print \"YES\" if the given tree is a Fib-tree, or \"NO\" otherwise. You can print your answer in any case. For example, if the answer is \"YES\", then the output \"Yes\" or \"yeS\" will also be considered as correct answer. Examples Input 3 1 2 2 3 Output YES Input 5 1 2 1 3 1 4 1 5 Output NO Input 5 1 3 1 2 4 5 3 4 Output YES Note In the first sample, we can cut the edge (1, 2), and the tree will be split into 2 trees of sizes 1 and 2 correspondently. Any tree of size 2 is a Fib-tree, as it can be split into 2 trees of size 1. In the second sample, no matter what edge we cut, the tree will be split into 2 trees of sizes 1 and 4. As 4 isn't F_k for any k, it's not Fib-tree. In the third sample, here is one possible order of cutting the edges so that all the trees in the process are Fib-trees: (1, 3), (1, 2), (4, 5), (3, 4). Here is a reference code to solve this task. You can use this to help you genereate cases or validate the solution. ```python #pragma GCC optimize(\"Ofast\") #pragma GCC target(\"sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2,fma\") #pragma GCC optimize(\"unroll-loops\") // #include // #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; // using namespace atcoder; typedef long long ll; typedef long double ld; typedef pair p32; typedef pair p64; typedef pair pp64; typedef pair pdd; typedef vector v64; typedef vector v32; typedef vector> vv32; typedef vector> vv64; typedef vector> vvp64; typedef vector vp64; typedef vector vp32; ll MOD = 1e9 + 7; double eps = 1e-12; #define forn(i, e) for (ll i = 0; i < e; i++) #define forsn(i, s, e) for (ll i = s; i < e; i++) #define rforn(i, s) for (ll i = s; i >= 0; i--) #define rforsn(i, s, e) for (ll i = s; i >= e; i--) #define ln '\n' #define dbg(x) cout << #x << \" = \" << x << ln #define mp make_pair #define pb push_back #define fi first #define se second #define INF 2e18 #define fast_cin() \ ios_base::sync_with_stdio(false); \ cin.tie(NULL); \ cout.tie(NULL) #define all(x) (x).begin(), (x).end() #define sz(x) ((ll)(x).size()) #define zero ll(0) #define set_bits(x) __builtin_popcountll(x) // #define mint modint998244353 ll mpow(ll a, ll b) { if (a == 0) return 0; if (b == 0) return 1; ll t1 = mpow(a, b / 2); t1 *= t1; t1 %= MOD; if (b % 2) t1 *= a; t1 %= MOD; return t1; } ll mpow(ll a, ll b, ll p) { if (a == 0) return 0; if (b == 0) return 1; ll t1 = mpow(a, b / 2, p); t1 *= t1; t1 %= p; if (b % 2) t1 *= a; t1 %= p; return t1; } ll modinverse(ll a, ll m) { ll m0 = m; ll y = 0, x = 1; if (m == 1) return 0; while (a > 1) { ll q = a / m; ll t = m; m = a % m, a = t; t = y; y = x - q * y; x = t; } if (x < 0) x += m0; return x; } mt19937_64 mt(chrono::steady_clock::now().time_since_epoch().count()); ll range(ll l, ll r) { return l + mt() % (r - l + 1); } ll rev(ll v) { return mpow(v, MOD - 2); } int LIM = 2e5 + 100; vv64 adj(LIM); v64 fib(1000, 1); v64 S(LIM, 0); vp64 edges(1); v64 active(1); int N; int node; void dfs(int n, int pa, int &idx, int k) { S[n] = 1; for (int c : adj[n]) { if (active[c] == 0) continue; p64 temp = edges[c]; int v; if (temp.fi == n) v = temp.se; else v = temp.fi; if (v == pa) continue; dfs(v, n, idx, k); if (S[v] == fib[k - 1] || S[v] == fib[k - 2]) { idx = c; node = v; } S[n] += S[v]; } } bool check(int n, int k) { if (k <= 2) return true; int idx = -1; dfs(n, -1, idx, k); // cout << \"a\" << endl; if (idx == -1) return false; active[idx] = 0; int u = edges[idx].fi, v = edges[idx].se; if (u == node) swap(u, v); // cout << n << \" \" << u << \" \" << v << endl; int k1, k2; k1 = k - 1; k2 = k - 2; if (S[v] == fib[k - 1]) swap(k1, k2); bool f1 = check(u, k1), f2 = check(v, k2); return f1 && f2; } void solve() { ll n; cin >> n; N = n; for (int i = 1; i < n; i++) { int u, v; cin >> u >> v; edges.push_back({u, v}); active.push_back(1); adj[u].push_back(i); adj[v].push_back(i); } int k = -1; for (int i = 1; i < 1000; i++) { if (fib[i] == n) { k = i; break; } } if (k == -1) { cout << \"NO\" << endl; return; } if (check(1, k)) { cout << \"YES\" << endl; } else { cout << \"NO\" << endl; } } int main() { fast_cin(); ll t = 1; for (int i = 2; i < 50; i++) { fib[i] = fib[i - 1] + fib[i - 2]; } // cin >> t; forn(i, t) { // cout << \"Case #\" << i+1 << \": \"; solve(); } return 0; } ``` 请完成上述谜题的训练场环境类实现,包括所有必要的方法。 """ from bootcamp import Basebootcamp import re import random from bootcamp import Basebootcamp class Efibtreebootcamp(Basebootcamp): def __init__(self, yes_prob=0.5, case_type=None, max_n=200000): super().__init__() self.yes_prob = yes_prob self.case_type = case_type self.max_n = max_n # 预计算斐波那契数列 self.fib = [1, 1] while True: next_f = self.fib[-1] + self.fib[-2] if next_f > max_n: break self.fib.append(next_f) self.fib_set = set(self.fib) def _build_fib_tree(self, k): """动态构建符合Fib-tree的随机结构""" if k == 0 or k == 1: return {'nodes': [1], 'edges': []} # 随机选择分割比例(允许不同分割方向) left_k = k-1 right_k = k-2 if random.random() < 0.5 and k >= 3: left_k, right_k = right_k, left_k left = self._build_fib_tree(left_k) right = self._build_fib_tree(right_k) # 动态计算节点偏移 max_left = max(left['nodes']) right_nodes = [n + max_left for n in right['nodes']] right_edges = [[u+max_left, v+max_left] for u, v in right['edges']] # 随机选择连接点 connect_point = random.choice(left['nodes']) new_node = max_left + 1 if not right['nodes'] else right_nodes[0] return { 'nodes': left['nodes'] + right_nodes, 'edges': left['edges'] + right_edges + [[connect_point, new_node]] } def case_generator(self): # 类型决策逻辑 if self.case_type is not None: generate_yes = (self.case_type == 'YES') else: generate_yes = random.random() < self.yes_prob if generate_yes: valid_ks = [k for k, f in enumerate(self.fib) if 1 <= f <= self.max_n and k >= 0] if not valid_ks: valid_ks = [0, 1] k = random.choice(valid_ks) n = self.fib[k] # 特殊处理小案例 if k <= 1: return {'n': n, 'edges': [], 'expected': 'YES'} tree = self._build_fib_tree(k) return { 'n': n, 'edges': tree['edges'], 'expected': 'YES' } else: # 生成两种NO案例类型 if random.random() < 0.5: # 类型A:n非斐波那契数 while True: n = random.randint(1, self.max_n) if n not in self.fib_set: break # 生成链式结构 edges = [[i, i+1] for i in range(1, n)] return {'n': n, 'edges': edges, 'expected': 'NO'} else: # 类型B:斐波那契数但结构非法 valid_ks = [k for k, f in enumerate(self.fib) if f >=5 and f <= self.max_n] k = random.choice(valid_ks) n = self.fib[k] # 生成星型结构 edges = [[1, i] for i in range(2, n+1)] return {'n': n, 'edges': edges, 'expected': 'NO'} @staticmethod def prompt_func(question_case): n = question_case['n'] edges = question_case['edges'] edge_list = '\n'.join(f"{u} {v}" for u, v in edges) return f"""判断给定的树是否为Fib-tree。规则如下: 1. 顶点数必须是斐波那契数(F_0=1, F_1=1, F_n=F_{{n-1}}+F_{{n-2}}) 2. 单个顶点或可通过移除一条边分割为两个Fib-tree 输入: {n} {edge_list} 请将答案(YES/NO)放在[answer]标签内,例如:[answer]YES[/answer]""" @staticmethod def extract_output(output): matches = re.findall(r'\[answer\](.*?)\[/answer\]', output, re.IGNORECASE) if not matches: return None answer = matches[-1].strip().upper() return answer if answer in {'YES', 'NO'} else None @classmethod def _verify_correction(cls, solution, identity): n = identity['n'] edges = identity['edges'] # 快速判断标记案例 if 'expected' in identity: return solution == identity['expected'] # 构建邻接表 adj = [[] for _ in range(n+1)] for u, v in edges: adj[u].append(v) adj[v].append(u) # 预计算斐波那契序列 fib = [1, 1] while fib[-1] < n: fib.append(fib[-1] + fib[-2]) if n not in fib: return solution == 'NO' k = fib.index(n) # 改进的递归验证算法 def validate(root, parent): size = 1 valid_splits = [] for child in adj[root]: if child == parent: continue child_size = validate(child, root) if child_size == -1: return -1 size += child_size valid_splits.append(child_size) # 基准情况 if size == 1: return 1 # 检查当前子树是否可分割 required = [fib[k-1], fib[k-2]] for s in valid_splits: if s in required: remaining = size - 1 - s # 减去当前根节点 if remaining in required: return size return -1 return (solution == 'YES') == (validate(1, -1) != -1)