[藍橋杯]堆的計數

堆的計數

題目描述

我們知道包含?NN?個元素的堆可以看成是一棵包含?NN?個節點的完全二叉樹。

每個節點有一個權值。對于小根堆來說,父節點的權值一定小于其子節點的權值。

假設?NN?個節點的權值分別是 1~NN,你能求出一共有多少種不同的小根堆嗎?

例如對于?NN?= 4 有如下 3 種:

1

/ \

2 3

/

4

1

/ \

3 2

/

4

1

/ \

2 4

/

3

由于數量可能超過整型范圍,你只需要輸出結果除以?109+9109+9?的余數。

輸入描述

輸入輸出一個整數?N?(1≤N≤105)N?(1≤N≤105)。

輸出描述

一個整數表示答案。

輸入輸出樣例

示例

輸入

4

輸出

3

運行限制

  • 最大運行時間:1s
  • 最大運行內存: 256M

總通過次數: 372??|??總提交次數: 543??|??通過率: 68.5%

難度: 困難???標簽: 2018, 快速冪, 省賽, 動態規劃

算法思路

要計算由 1~N 的 N 個不同數字組成的小根堆數量,我們需要利用組合數學和動態規劃。核心思路是:

  1. ??樹形結構??:完全二叉樹的結構固定,根節點為最小值 1
  2. ??子樹分配??:剩余 N-1 個數字需要分配到左右子樹
  3. ??遞歸計算??:每個子樹也必須滿足小根堆性質
  4. ??組合數學??:通過組合數計算分配方案,利用動態規劃避免重復計算
關鍵公式:

對于以節點 i 為根的子樹:

dp[i] = C(size[i]-1, size[left]) × dp[left] × dp[right] mod MOD

其中:

  • size[i]:子樹 i 的節點數
  • left/right:左右子節點
  • C(n,k):組合數,表示從 n 個元素選 k 個的方案數

算法演示

以 N=4 為例:

     1          1          1/ \        / \        / \2   3      3   2      2   4/          /          /4          4          3

三種不同的小根堆結構,均滿足父節點 < 子節點的性質。

代碼實現(C++)

#include <iostream>
#include <vector>
using namespace std;const long long MOD = 1000000009;
const int MAXN = 100010;long long fact[MAXN], invFact[MAXN];
int sizes[MAXN];
long long dp[MAXN];// 快速冪計算 a^b mod MOD
long long modExp(long long a, long long b) {long long res = 1;while (b) {if (b & 1) res = (res * a) % MOD;a = (a * a) % MOD;b >>= 1;}return res;
}// 預處理階乘和逆元
void precompute(int n) {fact[0] = invFact[0] = 1;for (int i = 1; i <= n; i++) {fact[i] = fact[i-1] * i % MOD;}invFact[n] = modExp(fact[n], MOD-2);for (int i = n-1; i >= 1; i--) {invFact[i] = invFact[i+1] * (i+1) % MOD;}
}// 計算組合數 C(n,k) mod MOD
long long nCr(int n, int k) {if (k < 0 || k > n) return 0;return fact[n] * invFact[k] % MOD * invFact[n-k] % MOD;
}int main() {int N;cin >> N;// 預處理階乘和逆元precompute(N);// 計算每個節點的子樹大小for (int i = N; i >= 1; i--) {sizes[i] = 1;int left = 2*i, right = 2*i+1;if (left <= N) sizes[i] += sizes[left];if (right <= N) sizes[i] += sizes[right];}// 初始化葉子節點的dp值for (int i = 1; i <= N; i++) {int left = 2*i, right = 2*i+1;if (left > N) dp[i] = 1; // 葉子節點}// 動態規劃計算dp值(從下往上)for (int i = N; i >= 1; i--) {int left = 2*i, right = 2*i+1;if (left <= N) { // 非葉子節點int left_size = sizes[left];int right_size = (right <= N) ? sizes[right] : 0;int total = sizes[i] - 1;long long comb = nCr(total, left_size);dp[i] = comb * dp[left] % MOD;if (right <= N) {dp[i] = dp[i] * dp[right] % MOD;}}}cout << dp[1] << endl;return 0;
}

算法步驟詳解

  1. ??預處理階乘和逆元??

    • 計算?0!?到?N!?的階乘數組?fact[]
    • 通過費馬小定理計算階乘的逆元數組?invFact[](因為 MOD 是質數)
  2. ??計算子樹大小??

    for (int i = N; i >= 1; i--) {sizes[i] = 1;if (2*i <= N) sizes[i] += sizes[2*i];if (2*i+1 <= N) sizes[i] += sizes[2*i+1];
    }
    • 從葉子節點向上計算每個節點的子樹大小
    • 節點 i 的子樹大小 = 1(自身) + 左子樹大小 + 右子樹大小
  3. ??初始化葉子節點??

    for (int i = 1; i <= N; i++) {if (2*i > N) dp[i] = 1; // 葉子節點方案數為1
    }
  4. ??動態規劃計算方案數??

    for (int i = N; i >= 1; i--) {if (非葉子節點) {int left_size = 左子樹大小;int total = sizes[i]-1; // 需要分配的總節點數long long comb = nCr(total, left_size); // 分配方案數dp[i] = comb * dp[左子節點] % MOD;dp[i] = dp[i] * dp[右子節點] % MOD; // 如果存在}
    }

實例驗證

??輸入 N=4 時:??

  1. 子樹大小計算:

    • 節點4:size=1(葉子)
    • 節點3:size=1(葉子)
    • 節點2:size=1 + size[4] = 2
    • 節點1:size=1 + size[2] + size[3] = 4
  2. DP 計算:

    • dp[4] = 1(葉子)
    • dp[3] = 1(葉子)
    • dp[2] = C(1,1) × dp[4] = 1×1 = 1
    • dp[1] = C(3,2) × dp[2] × dp[3] = 3×1×1 = 3

??輸出:3?? ?

注意事項

  1. ??組合數計算??

    • 使用預處理的階乘和逆元保證 O(1) 時間復雜度
    • 組合數公式:C(n,k)=k!(n?k)!n!?modMOD
  2. ??取模運算??

    • 所有乘法操作后立即取模,防止 long long 溢出
    • 使用?(a * b) % MOD?確保中間結果不溢出
  3. ??遍歷順序??

    • ??必須從后向前遍歷??(葉子→根)
    • 確保計算 dp[i] 時子節點的 dp 值已計算完成

測試點設計

  1. ??邊界值測試??

    • N=1:輸出 1(單節點堆)
    • N=2:輸出 1(唯一結構:根-左子)
    • N=3:輸出 2(兩種結構:根+左左/根+左右)
  2. ??完全二叉樹測試??

    • N=7(滿二叉樹):輸出 80
    • N=15(滿二叉樹):輸出 21964800
  3. ??性能測試??

    • N=10^5:在 1s 內完成計算
    • 最大組合數計算:C(10^5, 50000) mod MOD
  4. ??取模驗證??

    • 大 N 結果超過 long long 范圍
    • 確保所有操作正確取模

優化建議

  1. ??空間優化??

    // 使用 vector 替代靜態數組
    vector<long long> fact(MAXN), invFact(MAXN);
    vector<int> sizes(MAXN);
    vector<long long> dp(MAXN);
  2. ??組合數計算優化??

    // 使用盧卡斯定理處理更大的 N
    long long lucas(int n, int k) {if (k == 0) return 1;return nCr(n % MOD, k % MOD) * lucas(n / MOD, k / MOD) % MOD;
    }

  3. ??并行計算??

    // OpenMP 并行計算子樹大小
    #pragma omp parallel for
    for (int i = N; i >= 1; i--) {// 計算 sizes[i]
    }

  4. ??記憶化搜索??

    // 存儲已計算的子樹方案數
    unordered_map<int, long long> memo;
    if (memo.count(i)) return memo[i];

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

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

相關文章

論文閱讀:LLM4Drive: A Survey of Large Language Models for Autonomous Driving

地址&#xff1a;LLM4Drive: A Survey of Large Language Models for Autonomous Driving 摘要翻譯 自動駕駛技術作為推動交通和城市出行變革的催化劑&#xff0c;正從基于規則的系統向數據驅動策略轉變。傳統的模塊化系統受限于級聯模塊間的累積誤差和缺乏靈活性的預設規則。…

WebRTC中的幾個Rtp*Sender

一、問題&#xff1a; webrtc當中有幾個比較相似的類&#xff0c;看著都是發送RTP數據包的&#xff0c;分別是&#xff1a;RtpPacketToSend 和RtpSenderVideo還有RtpVideoSender以及RTPSender&#xff0c;這說明什么呢&#xff1f;首先&#xff0c;說明我會很多連詞&#xff0…

EFI(x64)簡易開發環境

文章目錄 1 必須文件2 運行環境3 構建應用 (Visual Studio)4 引用 EDK2 頭文件 1 必須文件 EDK2: 可以只拉取倉庫本身, 不拉取其子倉庫(完整構建才需要) qemu: qemu 以源碼發布, QEMU for Windows – Installers (64 bit) 這里有民間構建的安裝包 2 運行環境 創建一個 root …

八皇后問題深度解析

八皇后問題深度解析 一、八皇后問題的起源與背景1.1 問題起源1.2 歷史發展 二、問題描述與約束條件2.1 問題描述2.2 約束條件 三、算法原理&#xff1a;回溯算法3.1 回溯算法概述3.2 八皇后問題的回溯算法實現思路 四、八皇后問題的多語言實現4.1 Python實現4.2 C實現4.3 Java實…

Cursor 工具項目構建指南: Python 3.8 環境下的 Prompt Rules 約束

簡簡單單 Online zuozuo: 簡簡單單 Online zuozuo 簡簡單單 Online zuozuo 簡簡單單 Online zuozuo 簡簡單單 Online zuozuo :本心、輸入輸出、結果 簡簡單單 Online zuozuo : 文章目錄 Cursor 工具項目構建指南: Python 3.8 環境下的 Prompt Rules 約束前言項目簡介技術棧…

Java中的阻塞隊列

阻塞隊列是什么&#xff1f; 一、阻塞隊列的核心概念與特性 1.1 阻塞隊列是什么&#xff1f; 簡單來說&#xff0c;阻塞隊列是一種特殊的隊列&#xff0c;它具備普通隊列先進先出&#xff08;FIFO&#xff09;的特性&#xff0c;同時還支持兩個額外的重要操作&#xff1a; 當…

v1.0.1版本更新·2025年5月22日發布-優雅草星云物聯網AI智控系統

v1.0.1版本更新2025年5月22日發布-優雅草星云物聯網AI智控系統 開源地址 星云智控官網&#xff1a; 優雅草星云物聯網AI智控軟件-移動端vue: 優雅草星云物聯網AI智控軟件-移動端vue 星云智控PC端開源&#xff1a; 優雅草星云物聯網AI智控軟件-PC端vue: 優雅草星云物聯網AI…

Java-IO流之轉換流詳解

Java-IO流之轉換流詳解 一、轉換流概述1.1 什么是轉換流1.2 轉換流的作用1.3 轉換流的位置 二、InputStreamReader詳解2.1 基本概念2.2 構造函數2.3 核心方法2.4 使用示例&#xff1a;讀取不同編碼的文件 三、OutputStreamWriter詳解3.1 基本概念3.2 構造函數3.3 核心方法3.4 使…

android lifeCycleOwner生命周期

一 Fragment中 viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) 什么時候執行&#xff1f; 讓我分析一下相關問題&#xff1a; 關于 onPause 時的數據更新: viewLifecycleOwner.lifecycleScope.launch {viewLifecycleOwner.repeatOnLifecycle(Lifecycle.Sta…

Liunx進程替換

文章目錄 1.進程替換2.替換過程3.替換函數exec3.1命名解釋 4.細說6個exe函數execl函數execvexeclp、execvpexecle、execve 1.進程替換 fork&#xff08;&#xff09;函數在創建子進程后&#xff0c;子進程如果想要執行一個新的程序&#xff0c;就可以使用進程的程序替換來完成…

【華為云Astro-服務編排】服務編排中圖元的使用與配置

目錄 子服務編排圖元 子服務編排圖元的作用 如何使用子服務編排圖元 腳本圖元 腳本圖元的作用 如何使用腳本圖元 記錄創建圖元 記錄創建圖元的作用 如何使用記錄創建圖元 記錄刪除圖元 記錄刪除圖元的作用 如何使用記錄刪除圖元 記錄查詢圖元 記錄查詢圖元的作用…

SQL Server相關的sql語句

目錄 一、數據定義語言&#xff08;DDL&#xff09;1. 創建數據庫2. 修改數據庫3. 刪除數據庫4. 創建表5. 修改表結構6. 刪除表 二、數據操作語言&#xff08;DML&#xff09;1. 插入數據2. 更新數據3. 刪除數據 三、數據查詢語言&#xff08;DQL&#xff09;1. 基礎查詢2. 去重…

【Hot 100】55. 跳躍游戲

目錄 引言跳躍游戲我的解題 &#x1f64b;?♂? 作者&#xff1a;海碼007&#x1f4dc; 專欄&#xff1a;算法專欄&#x1f4a5; 標題&#xff1a;【Hot 100】55. 跳躍游戲?? 寄語&#xff1a;書到用時方恨少&#xff0c;事非經過不知難&#xff01; 引言 跳躍游戲 &#x…

基于51單片機的車內防窒息檢測報警系統

目錄 具體實現功能 設計介紹 資料內容 全部內容 資料獲取 具體實現功能 具體實現功能&#xff1a; &#xff08;1&#xff09;檢測車內溫度及二氧化碳濃度并用lcd1602實時顯示。 &#xff08;2&#xff09;當人體紅外傳感器檢測到車內有人&#xff0c;且溫度或二氧化碳濃度…

關于智能體API參考接口

關于智能體在Flask的源碼&#xff1a;請求體(在payload里的是請求體)、請求頭&#xff08;在headers里的i局勢請求頭&#xff09;。 我的例子&#xff1a; 我的疑問&#xff1a;為什么沒按Coze官方API文檔格式&#xff0c;在Apifox里發POST請求卻能收到回復&#xff1f; 1. 你…

Excel 批量下載PDF、批量下載考勤圖片——仙盟創夢IDE

在辦公場景中&#xff0c;借助應用軟件實現 Excel 批量處理考勤圖片、電子文檔與 PDF&#xff0c;具有諸多顯著優勢。 從考勤圖片處理來看&#xff0c;通過 Excel 批量操作&#xff0c;能快速提取圖片中的考勤信息&#xff0c;如員工打卡時間、面部識別數據等&#xff0c;節省…

Apache Doris + MCP:Agent 時代的實時數據分析底座

一、Apache Doris&#xff1a;面向 Agent 時代的智能數據平臺 當我們談論 2025 年時&#xff0c;業界普遍認為這將是"Agent 革命年"&#xff08;Agentic Revolution&#xff09;的開端。與傳統的人機交互模式不同&#xff0c;AI Agent 作為一個全新的"用戶角色…

能不能用string接收數據庫的datetime類型字段

在Java中使用String類型通過MyBatis接收MySQL的datetime類型字段時&#xff0c;?可以正常工作&#xff0c;但需注意格式和潛在問題。以下是關鍵點&#xff1a; 1. ?直接轉換是可行的? MySQL的datetime字段&#xff08;如 2023-10-05 12:34:56&#xff09;會被MyBatis自動轉…

【Python訓練營打卡】day44 @浙大疏錦行

DAY 44 預訓練模型 知識點回顧&#xff1a; 1. 預訓練的概念 2. 常見的分類預訓練模型 3. 圖像預訓練模型的發展史 4. 預訓練的策略 5. 預訓練代碼實戰&#xff1a;resnet18 作業&#xff1a; 1. 嘗試在cifar10對比如下其他的預訓練模型&#xff0c;觀察差異&#xff0c;…

MySQL中關于事務和鎖的常見執行命令整理包括版本區別

MySQL中關于事務和鎖的常見執行命令實例整理&#xff0c;并標注了不同版本下的區別&#xff08;如MySQL 8.0與舊版本的差異&#xff09;&#xff1a; 一、事務相關命令 1. 事務控制 命令描述版本差異START TRANSACTION; 或 BEGIN;顯式開啟事務通用語法&#xff0c;無版本差異…