日常訓練 最小生成樹

2021-08-04 02:12:49 字數 1651 閱讀 2955

【問題描述】

話說正在jmy愁苦如何籌錢給大家買汽水的時候,他遇上了一位魔法師。魔法師希望jmy能幫他破解魔法書的咒語。如果jmy做到了,就幫他付所有買汽水的錢。

魔法書上畫了乙個完全圖(每兩個點之間有且只有一條邊),每個點都有乙個獨一無二的[1,n]內的編號,jmy的任務是要找到最小生成樹,以此作為魔法樹,從而破解咒語。

對於完全圖的邊(i,j)(i≠j)的邊權恰好就等於i,j 兩個數字的最大公約數。

特別地,要作為魔法樹,必須滿足樹指定某個點為根後,所有除根以外的節點的父親的標號必須小於自身標號。

jmy一眼就看出了最小生成樹的邊權和。然而咒語卻是最小生成樹的個數。

為了保證大家都有汽水喝,你能幫幫jmy嗎?

【輸入格式】

一行僅乙個數n表示完全圖的大小。

【輸出格式】

一行乙個整數表示答案對100,000,007取mod的結果。

【輸入輸出樣例】

mst.in

3 mst.out

2【資料規模】

對於10%的資料n≤5

對於30%的資料n≤8

對於40%的資料n≤10

對於70%的資料n≤5,000

對於100%的資料n≤20,000

【分析】

首先肯定存在一種最小生成樹方案:令點1為根,向其餘每個點連邊。也就是說,所有的最小生成樹方案都滿足所有的邊權為1。又因為「所有除根以外的節點的父親的標號必須小於自身標號」,所以我們考慮按照編號順序構造最小生成樹。那麼如果當前的生成樹中已經包含點

1 ~i−

1,則點

i 可選擇向任意乙個與

i互質的點連邊。

我們記f[i

] 表示已經最小生成樹包含點

i 的方案個數,則轉移為 f[

i]=f

[i−1

]×(點1

~i−1

中與點i

互質的點的個數)

我們記cnt

[i]表示互質點的個數,問題的關鍵在於如何求出cn

t[i]

。 一開始先假設cn

t[i]

=i−1

,即前面的所有數都與它互質,然後扣除掉那些不合法的方案。記

i 的倍數k=

i×j(

j≥2)

,則cnt

[k]−

=cnt

[i] ,表示所有與

i 互質的數乘以

j後必然與i×

j 不互質,所以要扣除。因為這樣是從互質的個數來轉移,

j 為i×

j和與i 互質的數乘以

j後的最大公約數,所以不會算重。

【**】

#include 

#include

using

namespace

std;

typedef

long

long ll;

const ll mod = 1e8 + 7;

const

int n = 2e4 + 5;

ll f[n], cnt[n]; bool vis[n];

int n, m, a[n];

int main()

最小生成樹訓練總結

最小生成樹簡單概念 在數個點間,兩點之間存在權值,求若涉及所有的點時,權值之和最小。常用演算法 1.prim演算法 首先將每乙個點之間的距離都定為最大值,把第乙個點的最小距離設為零,在與第乙個點有聯絡的每乙個點中找出權值最小的點,依此規律進行迴圈,直到找到所有的點。例 最優佈線問題中的迴圈部分 fo...

最小生成樹 次小生成樹

一 最小生成樹 說到生成樹首先要解釋一下樹,樹是乙個聯通的無向無環圖,多棵樹的集合則被稱為森林。因此,樹具有許多性質 1.兩點之間的路徑是唯一的。2.邊數等於點數減一。3.連線任意兩點都會生成乙個環。對於乙個無向聯通圖g的子圖,如果它包含g的所有點,則它被稱為g的生成樹,而各邊權和最小的生成樹則被稱...

最小生成樹

package 圖 最小生成樹是用最少的邊吧把所有的節點連線起來。於是和圖的深度優先搜素差不多。class stack public void push int key public int pop 檢視棧頂的元素 public int peek public boolean isempty cla...