2025.05.17淘天機考筆試真題第三題

📌 點擊直達筆試專欄 👉《大廠筆試突圍》

💻 春秋招筆試突圍在線OJ 👉 筆試突圍OJ

03. 奇偶平衡樹分割問題

問題描述

K小姐是一位園林設計師,她設計了一個由多個花壇組成的樹形公園。每個花壇中種植了不同數量的花,數量由整數表示。K小姐發現,當公園被分割成多個獨立區域時,如果每個區域中的花朵總數都是偶數,游客會感到更加和諧。

現在,K小姐想要通過關閉若干條連接花壇的小路(即刪除樹的邊),將公園分割成若干個獨立區域(連通塊),使得每個區域內的花朵總數都是偶數。

請你求出,對于每個 k ( 1 ≤ k ≤ n ? 1 ) k (1 \leq k \leq n-1) k(1kn?1),關閉 k k k 條小路后得到的 k + 1 k+1 k+1 個獨立區域滿足條件的方案數。如果不存在滿足條件的方案,對應的答案記為 0 0 0

注意:兩種關閉小路的方案若關閉的路徑集合不同,則視為不同的方案。

輸入格式

第一行給出一個整數 n n n,表示花壇的數量。

第二行給出 n n n 個整數 W 1 , W 2 , . . . , W n W_1, W_2, ..., W_n W1?,W2?,...,Wn?,其中 W i W_i Wi? 表示第 i i i 個花壇中的花朵數量。

接下來 n ? 1 n-1 n?1 行,每行包含兩個整數 u u u v ( 1 ≤ u , v ≤ n , u ≠ v ) v (1 \leq u, v \leq n, u \neq v) v(1u,vn,u=v),表示花壇 u u u 與花壇 v v v 之間有一條小路,保證給定的圖構成一棵樹。

輸出格式

輸出 n ? 1 n-1 n?1 個數,第 i i i 個數表示關閉 i i i 條小路后滿足條件的方案數。由于答案可能非常大,請對答案取模 1 0 9 + 7 10^9+7 109+7 后輸出。

樣例輸入

5
1 2 3 4 4
1 2
1 3
2 4
2 5

樣例輸出

3 3 1 0
樣例解釋說明
樣例1 k = 1 k=1 k=1 時,關閉方案有 {(1,2)}, {(2,4)}, {(2,5)},共 3 種。
k = 2 k=2 k=2 時,關閉方案有 {(1,2), (2,4)}, {(1,2), (2,5)}, {(2,5), (2,4)},共 3 種。
k = 3 k=3 k=3 時,關閉方案有 {(1,2), (2,4), (2,5)},共 1 種。
k = 4 k=4 k=4 時,沒有滿足條件的方案。

數據范圍

  • 2 ≤ n ≤ 1 0 5 2 \leq n \leq 10^5 2n105
  • 1 ≤ W i ≤ 1 0 9 1 \leq W_i \leq 10^9 1Wi?109
  • 1 ≤ u , v ≤ n 1 \leq u, v \leq n 1u,vn

題解

這道題乍看復雜,但仔細分析后會發現其中的數學規律和解決方案。

首先,我們需要理解什么情況下一個連通塊的花朵數能夠為偶數。顯然,如果一個連通塊內奇數花壇的個數為偶數,那么總花朵數一定是偶數(偶數+偶數=偶數,奇數+奇數=偶數)。

我們的目標是通過刪除邊,將樹分成多個連通塊,使得每個連通塊內的奇數花壇數量都是偶數。那么問題轉化為:找出那些刪除后能讓兩側奇數花壇數量都是偶數的邊。

關鍵觀察:一個連通塊內奇數花壇數量為奇數時,無論如何分割,都無法使所有子連通塊內的奇數花壇數量都為偶數。因為奇數個奇數,無論如何分組,總有一組含有奇數個奇數。

因此,如果整棵樹中奇數花壇的總數為奇數,則無解。

接下來,我們定義一個邊是"好邊",如果刪除這條邊后,兩個連通塊內的奇數花壇數量都是偶數。一條邊是好邊當且僅當這條邊連接的子樹內奇數花壇數量為偶數。

如果好邊數量為g,那么要刪除k條邊使所有連通塊花朵數為偶數,就相當于從g條好邊中選擇k條,即組合數C(g,k)。

具體算法如下:

  1. 統計整棵樹中奇數花壇的總數,如果為奇數,則無解。
  2. 通過DFS計算每個子樹中奇數花壇的數量。
  3. 檢查每條邊,如果刪除后兩側連通塊中奇數花壇數量都是偶數,則該邊為好邊。
  4. 計算從g條好邊中選k條的組合數C(g,k),即為答案。

時間復雜度分析:

  • DFS遍歷樹的復雜度為O(n)
  • 檢查每條邊的復雜度為O(n)
  • 計算組合數的復雜度為O(n)
    總體時間復雜度為O(n),空間復雜度為O(n)。

參考代碼

  • Python
import sys
input = lambda: sys.stdin.readline().strip()def solve():# 讀取輸入n = int(input())w = [0] + list(map(int, input().split()))adj = [[] for _ in range(n+1)]for _ in range(n-1):u, v = map(int, input().split())adj[u].append(v)adj[v].append(u)# 計算奇數花壇的總數odd_count = sum(1 for val in w[1:] if val % 2 == 1)# 如果奇數花壇總數為奇數,則無解if odd_count % 2 == 1:print(" ".join(["0"] * (n-1)))return# 計算子樹中奇數花壇的數量t = [0] * (n+1)good_edges = 0# DFS計算子樹信息def dfs(node, parent):nonlocal good_edgesis_odd = w[node] % 2  # 當前節點是否為奇數for child in adj[node]:if child != parent:# 遞歸計算子樹dfs(child, node)# 更新當前節點的奇數計數is_odd ^= t[child]t[node] = is_odd# 檢查是否為好邊if parent != 0 and t[node] == 0:good_edges += 1# 從根節點開始DFSdfs(1, 0)# 計算組合數MOD = 10**9 + 7# 預計算階乘和逆元fact = [1] * (n+1)inv_fact = [1] * (n+1)for i in range(1, n+1):fact[i] = (fact[i-1] * i) % MOD# 計算逆元(使用費馬小定理)def pow_mod(x, p):res = 1while p > 0:if p & 1:res = (res * x) % MODx = (x * x) % MODp >>= 1return resinv_fact[n] = pow_mod(fact[n], MOD - 2)for i in range(n, 0, -1):inv_fact[i-1] = (inv_fact[i] * i) % MOD# 計算組合數C(n,k)def comb(n, k):if k < 0 or k > n:return 0return (fact[n] * inv_fact[k] % MOD * inv_fact[n-k] % MOD)# 計算并輸出結果result = []for k in range(1, n):ans = comb(good_edges, k)result.append(str(ans))print(" ".join(result))if __name__ == "__main__":solve()
  • Cpp
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 1e9 + 7;// 快速冪計算a^b mod MOD
ll pow_mod(ll a, ll b) {ll res = 1;while (b > 0) {if (b & 1) res = (res * a) % MOD;a = (a * a) % MOD;b >>= 1;}return res;
}int main() {ios::sync_with_stdio(false);cin.tie(nullptr);int n;cin >> n;// 讀取花壇權值vector<int> w(n+1);for (int i = 1; i <= n; i++) cin >> w[i];// 構建樹vector<vector<int>> adj(n+1);for (int i = 0; i < n-1; i++) {int u, v;cin >> u >> v;adj[u].push_back(v);adj[v].push_back(u);}// 計算奇數花壇總數int tot_odd = 0;for (int i = 1; i <= n; i++)tot_odd += (w[i] & 1);// 如果奇數總數為奇數,無解if (tot_odd & 1) {for (int k = 1; k <= n-1; k++)cout << "0" << (k == n-1 ? '\n' : ' ');return 0;}// 存儲子樹奇數數量vector<int> t(n+1, 0);int good = 0; // 好邊數量// DFS計算子樹信息vector<bool> vis(n+1, false);function<void(int, int)> dfs = [&](int u, int p) {int odd = w[u] & 1; // 當前節點是否為奇數for (int v : adj[u]) {if (v != p) {dfs(v, u);odd ^= t[v]; // 更新奇數計數}}t[u] = odd;// 檢查是否為好邊if (p != 0 && t[u] == 0)good++;};dfs(1, 0);// 預計算階乘和逆元vector<ll> fact(n+1, 1), inv_fact(n+1, 1);for (int i = 1; i <= n; i++)fact[i] = (fact[i-1] * i) % MOD;inv_fact[n] = pow_mod(fact[n], MOD-2); // 費馬小定理for (int i = n; i >= 1; i--)inv_fact[i-1] = (inv_fact[i] * i) % MOD;// 組合數計算函數auto comb = [&](int n, int k) -> ll {if (k < 0 || k > n) return 0;return (fact[n] * inv_fact[k] % MOD * inv_fact[n-k] % MOD);};// 輸出結果for (int k = 1; k <= n-1; k++) {ll res = comb(good, k);cout << res << (k == n-1 ? '\n' : ' ');}return 0;
}
  • Java
import java.io.*;
import java.util.*;public class Main {static final int MOD = (int)1e9 + 7;public static void main(String[] args) throws IOException {BufferedReader br = new BufferedReader(new InputStreamReader(System.in));// 讀取花壇數量int n = Integer.parseInt(br.readLine().trim());// 讀取每個花壇的花朵數String[] vals = br.readLine().trim().split(" ");int[] w = new int[n+1];for (int i = 1; i <= n; i++) {w[i] = Integer.parseInt(vals[i-1]);}// 構建樹List<Integer>[] adj = new ArrayList[n+1];for (int i = 0; i <= n; i++) {adj[i] = new ArrayList<>();}for (int i = 0; i < n-1; i++) {String[] edge = br.readLine().trim().split(" ");int u = Integer.parseInt(edge[0]);int v = Integer.parseInt(edge[1]);adj[u].add(v);adj[v].add(u);}// 計算奇數花壇總數int oddCount = 0;for (int i = 1; i <= n; i++) {if (w[i] % 2 == 1) {oddCount++;}}// 如果奇數總數為奇數,無解if (oddCount % 2 == 1) {StringBuilder sb = new StringBuilder();for (int k = 1; k <= n-1; k++) {sb.append("0");if (k < n-1) sb.append(" ");}System.out.println(sb.toString());return;}// 存儲子樹奇數數量和好邊數量int[] t = new int[n+1];int[] good = new int[1]; // 用數組便于在DFS中修改// DFS計算子樹信息dfs(1, 0, w, adj, t, good);// 預計算階乘和逆元long[] fact = new long[n+1];long[] invFact = new long[n+1];fact[0] = 1;for (int i = 1; i <= n; i++) {fact[i] = (fact[i-1] * i) % MOD;}invFact[n] = powMod(fact[n], MOD-2);for (int i = n; i > 0; i--) {invFact[i-1] = (invFact[i] * i) % MOD;}// 輸出結果StringBuilder result = new StringBuilder();for (int k = 1; k <= n-1; k++) {long ans = combination(good[0], k, fact, invFact);result.append(ans);if (k < n-1) result.append(" ");}System.out.println(result.toString());}// DFS計算子樹信息static void dfs(int node, int parent, int[] w, List<Integer>[] adj, int[] t, int[] good) {int isOdd = w[node] % 2; // 當前節點是否為奇數for (int child : adj[node]) {if (child != parent) {dfs(child, node, w, adj, t, good);isOdd ^= t[child]; // 更新奇數計數}}t[node] = isOdd;// 檢查是否為好邊if (parent != 0 && t[node] == 0) {good[0]++;}}// 快速冪計算static long powMod(long a, int b) {long res = 1;while (b > 0) {if ((b & 1) == 1) res = (res * a) % MOD;a = (a * a) % MOD;b >>= 1;}return res;}// 計算組合數C(n,k)static long combination(int n, int k, long[] fact, long[] invFact) {if (k < 0 || k > n) return 0;return (fact[n] * invFact[k] % MOD * invFact[n-k] % MOD);}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/80313.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/80313.shtml
英文地址,請注明出處:http://en.pswp.cn/web/80313.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

第三十五節:特征檢測與描述-ORB 特征

1. 引言:為什么需要ORB? 在計算機視覺領域,特征檢測與描述是許多任務(如圖像匹配、目標跟蹤、三維重建等)的核心基礎。傳統的算法如SIFT(尺度不變特征變換)和SURF(加速穩健特征)因其優異的性能被廣泛應用,但它們存在兩個顯著問題: 專利限制:SIFT和SURF受專利保護,…

深入解讀WPDRRC信息安全模型:構建中國特色的信息安全防護體系

目錄 前言1 WPDRRC模型概述2 模型結構詳解2.1 預警&#xff08;Warning&#xff09;2.2 保護&#xff08;Protect&#xff09;2.3 檢測&#xff08;Detect&#xff09;2.4 響應&#xff08;React&#xff09;2.5 恢復&#xff08;Restore&#xff09;2.6 反擊&#xff08;Count…

《算法導論(第4版)》閱讀筆記:p82-p82

《算法導論(第4版)》學習第 17 天&#xff0c;p82-p82 總結&#xff0c;總計 1 頁。 一、技術總結 1. Matrix Matrices(矩陣) (1)教材 因為第 4 章涉及到矩陣&#xff0c;矩陣屬于線性代數(linear algebra)范疇&#xff0c;如果不熟悉&#xff0c;可以看一下作者推薦的兩本…

基于Spring Boot和Vue的在線考試系統架構設計與實現(源碼+論文+部署講解等)

源碼項目獲取聯系 請文末卡片dd我獲取更詳細的演示視頻 系統介紹 基于Spring Boot和Vue的在線考試系統。為學生和教師/管理員提供一個高效、便捷的在線學習、考試及管理平臺。系統采用前后端分離的架構&#xff0c;后端基于成熟穩定的Spring Boot框架&#xff0c;負責數據處理…

Codeforces Round 1024 (Div.2)

比賽鏈接&#xff1a;CF1024 A. Dinner Time 只有當 n n n 是 p p p 的倍數而且 n ? q p ? m \frac{n \cdot q}{p} \not m pn?q?m 時輸出 NO&#xff0c;其余情況均滿足條件。 時間復雜度&#xff1a; O ( 1 ) O(1) O(1)。 #include <bits/stdc.h> using na…

【LeetCode 熱題 100】二叉樹的最大深度 / 翻轉二叉樹 / 二叉樹的直徑 / 驗證二叉搜索樹

??個人主頁&#xff1a;小羊 ??所屬專欄&#xff1a;LeetCode 熱題 100 很榮幸您能閱讀我的文章&#xff0c;誠請評論指點&#xff0c;歡迎歡迎 ~ 目錄 二叉樹的中序遍歷二叉樹的最大深度翻轉二叉樹對稱二叉樹二叉樹的直徑二叉樹的層序遍歷將有序數組轉換為二叉搜索樹驗…

Tomcat發布websocket

一、tomcal的lib放入文件 tomcat-websocket.jar websocket-api.jar 二、代碼示例 package com.test.ws;import com.test.core.json.Jmode;import javax.websocket.*; import javax.websocket.server.ServerEndpoint; import java.util.concurrent.CopyOnWriteArraySet; imp…

LLM筆記(二)LLM數據基礎-分詞算法(2)

文章目錄 1. 分詞算法概述1.1 基于詞典的&#xff08;或基于規則的&#xff09;分詞算法1.2 基于統計的&#xff08;或基于機器學習的&#xff09;分詞算法1.3 基于深度學習的分詞算法1.4 子詞&#xff08;Subword&#xff09;分詞算法1.5 混合分詞算法1.6 針對不同語言的特點 …

Uniapp開發鴻蒙應用時如何運行和調試項目

經過前幾天的分享&#xff0c;大家應該應該對uniapp開發鴻蒙應用的開發語法有了一定的了解&#xff0c;可以進行一些簡單的應用開發&#xff0c;今天分享一下在使用uniapp開發鴻蒙應用時怎么運行到鴻蒙設備&#xff0c;并且在開發中怎么調試程序。 運行 Uniapp項目支持運行到…

數據湖與數據倉庫融合:Hudi、Iceberg、Delta Lake 實踐對比

在實時與離線一體化的今天,數據湖與數據倉庫邊界不斷融合,越來越多企業選用如 Hudi、Iceberg、Delta Lake 等開源方案實現統一的數據存儲、計算、分析平臺。本篇將圍繞以下關鍵點,展開實戰對比與解決方案分享: ? 實時寫入能力 ? ACID 保證 ? 增量數據處理能力 ? 流批一…

Python爬蟲(29)Python爬蟲高階:動態頁面處理與云原生部署全鏈路實踐(Selenium、Scrapy、K8s)

目錄 引言&#xff1a;動態爬蟲的技術挑戰與云原生機遇一、動態頁面處理&#xff1a;Selenium與Scrapy的協同作戰1.1 Selenium的核心價值與局限1.2 Scrapy-Selenium中間件開發1.3 動態分頁處理實戰&#xff1a;京東商品爬蟲 二、云原生部署&#xff1a;Kubernetes架構設計與優化…

數據結構(十)——排序

一、選擇排序 1.簡單選擇排序 基本思想&#xff1a;假設排序表為[1,…,n]&#xff0c;第i趟排序即從[i,…,n]中選擇關鍵字最小的元素與L[i]交換 eg&#xff1a;給定關鍵字序列{87&#xff0c;45&#xff0c;78&#xff0c;32&#xff0c;17&#xff0c;65&#xff0c;53&…

小結:jvm 類加載過程

類加載過程 是Java虛擬機&#xff08;JVM&#xff09;將字節碼文件&#xff08;.class文件&#xff09;加載到內存中&#xff0c;并轉換為運行時數據結構的過程。這個過程可以分為多個步驟&#xff0c;每個步驟都有其特定的任務和目的。根據你提供的信息&#xff0c;以下是類加…

2024 山東省ccpc省賽

目錄 I&#xff08;簽到&#xff09; 題目簡述&#xff1a; 思路&#xff1a; 代碼&#xff1a; A&#xff08;二分答案&#xff09; 題目簡述&#xff1a; 思路&#xff1a; 代碼&#xff1a; K&#xff08;構造&#xff09; 題目&#xff1a; 思路&#xff1a; 代…

turn.js與 PHP 結合使用來實現 PDF 文件的頁面切換效果

將 Turn.js 與 PHP 結合使用來實現 PDF 文件的頁面切換效果&#xff0c;你需要一個中間步驟將 PDF 轉換為 Turn.js 可以處理的格式&#xff08;如 HTML 頁面或圖片&#xff09;。以下是實現這一功能的步驟和示例代碼&#xff1a; 步驟 1: 安裝必要的庫 首先&#xff0c;你需要…

Python實現NOA星雀優化算法優化卷積神經網絡CNN回歸模型項目實戰

說明&#xff1a;這是一個機器學習實戰項目&#xff08;附帶數據代碼文檔視頻講解&#xff09;&#xff0c;如需數據代碼文檔視頻講解可以直接到文章最后關注獲取。 1.項目背景 在當今數據驅動的時代&#xff0c;卷積神經網絡&#xff08;CNN&#xff09;不僅在圖像分類任務中…

(面試)View相關知識

1、View繪制流程 onMeasure() 確定View的測量寬高。onLayout() 確定View的最終寬高和四個頂點的位置。onDraw() 將View 繪制到屏幕上。 2、MeasureSpec有三種測量模式&#xff1a; 2.1. EXACTLY&#xff08;精確模式&#xff09; 含義&#xff1a;父容器明確指定了子View的精…

數組名既可作為指針也可作為變量名

在C語言中&#xff0c;數組名在不同的上下文中既可以作為指向數組首個元素的指針&#xff0c;也可以代表整個數組&#xff0c;這是由C語言的設計和語法規則決定的&#xff0c;下面我來詳細解釋一下。 1. 數組名作為指向首元素的指針 在大多數情況下&#xff0c;當數組名出現在…

Java異常、泛型與集合框架實戰:從基礎到應用

在Java編程的世界里&#xff0c;異常處理、泛型和集合框架是構建高效、健壯應用的關鍵技術。通過掌握這些技術&#xff0c;我們可以更好地管理程序運行時的錯誤&#xff0c;提高代碼的復用性和類型安全性。今天&#xff0c;我將通過一系列實驗&#xff0c;分享如何在Java中使用…

Spring源碼之解決循環依賴 三級緩存

目錄 三級緩存核心原理 循環依賴的解決過程 1. Bean A創建過程中提前曝光工廠 2. Bean B創建時發現依賴A&#xff0c;從緩存獲取 3. Bean A繼續完成初始化 三級緩存的作用總結 二級緩存為何不夠解決緩存依賴&#xff1f; 三級緩存如何解決&#xff1f; 為什么不直接在…