BZOJ1005 HNOI2008 明明的煩惱

2021-07-15 21:55:05 字數 2741 閱讀 6765

time limit: 1 sec  

memory limit: 162 mb

自從明明學了樹的結構,就對奇怪的樹產生了興趣......給出標號為1到n的點,以及某些點最終的度數,允許在

任意兩點間連線,可產生多少棵度數滿足要求的樹?

第一行為n(0 < n < = 1000),

接下來n行,第i+1行給出第i個節點的度數di,如果對度數不要求,則輸入-1

乙個整數,表示不同的滿足要求的樹的個數,無解輸出031

-1-1

2兩棵樹分別為1-2-3;1-3-2

解答這道題需要用到乙個叫perfur sequence(以下簡稱ps)的知識,對於一顆有n個節點的樹,它與乙個長度為n-2的ps一一對應,那麼它們的對應方式如何呢?

將一棵樹轉化為ps:

假設我們有一顆樹,其中有如下邊:1-2,1-3,2-4,2-5,3-6,3-7(其實就是節點標號1~7的完全二叉樹),我們先取標號最小的葉子節點4,記錄此時與其相連的節點,得到了ps的第一位數字:2,然後刪除節點4。按照上面的步驟,取5得2,取2得1,取1得3,取6得3。我們這個時候就得到了這個長為5的ps:2 2 1 3 3,顯然,對於一棵樹只能得到乙個ps,也就是每棵樹只對應乙個ps。

將乙個ps轉化為樹:

使用上面的ps:2 2 1 3 3 。首先這是乙個長為5的ps,那就意味這這棵樹有7個節點,顯然由上面我們可以知道每個節點的度數=它在ps中出現過的次數+1 。於是我們對於每乙個節點建立乙個表來描述它們的權值:

1   2   3   4   5   6   7

2   3   3   1   1   1   1

此時取度數為1的標號最小的節點4,使其與ps中的第一位數字對應標號的節點2相連,建邊4-2,然後刪除ps中第一位數字2,此時ps為2 1 3 3,同時在表中將2和4的權值分別減去1:

1   2   3   4   5   6   7

2   2   3   0   1   1   1

節點5與節點2相連,建邊5-2,ps變為1 3 3,權值表變為:

1   2   3   4   5   6   7

2   1   3   0   0   1   1

節點2與節點1相連,建邊2-1,ps變為3 3,權值表變為:

1   2   3   4   5   6   7 1

0   3   0   0   1   1

節點1與節點3相連,建邊1-3,ps變為3,權值表變為:

1   2   3   4   5   6   7

0   0   2   0   0   1   1

節點6與節點3相連,建邊6-3,ps清空,權值表變為:

1   2   3   4   5   6   7

0   0   1   0   0   0   1

最後在連線節點3與節點7,得到下面這些邊:4-2、5-2、2-1、1-3、6-3、7-3,很容易看出這就是我們上面的那顆樹。

在轉換過程中我們能發現,ps編碼生成的樹是唯一的,結合上面的結論,我們得出了ps編碼的性質:乙個ps編碼和一棵樹一一對應。

有了這個知識後,我們該如何解決這個問題呢?

首先,無解的情況很好判斷,這裡就不過多說明了。

對於有解的情況,由上面的過程我們知道,乙個節點的度數-1等於它在ps中出現過的次數,假設我們有m個度數有限制的點,分別為d[i]。

設:sum=∑(d[i]-1),(1<=i<=m)。

那麼對於乙個ps,不同排列的種數為:

c(m,n-2)*((sum!)/(∏(d[i]-1)!)),(1<=i<=m)。

對於剩下的n-2-m個位置,我們就可以隨意排列剩下的n-m個點,於是總的方案就是:

c(m,n-2)*((sum!)/(

∏(d[i]-1)!

))*(n-m)^(n-2-m),(1<=i<=m)

這就是有解的情況下的答案,高精度是必須的。

**:

#include#define mod 1000000

#define ll long long

using namespace std;

int n,m,tot,cnt,d[1005],num[1005],pri[1005],ans[1005],l=1;

bool jud(int x)

void getpri()

void solve(int a,int f)}}

}void mul(int x)

while (ans[l+1]>0) }

int main()

for (int i=1 ; i<=n ; i++)

if (d[i]==-1)

m++;

else

}if(tot>n-2)

solve(n-2,1);

solve(n-2-tot,-1);

for(int i=1;i<=n;i++)

if(d[i])

solve(d[i],-1);

for(int i=1;i<=cnt;i++)

while(num[i]--)

mul(pri[i]);

for(int i=1;i<=n-2-tot;i++)

mul(m);

for(int i=l;i>0;i--)

if(i==l)

printf("%d",ans[i]);

else

printf("%06d",ans[i]);

return 0;

}

狡猾的商人 bzoj1202,HNOI2005

ac通道 分析 因為每月的總收入可以為正,也可以為負,所以要比較兩個區間是否相符,當且僅當它們邊界都相同時才能比較。我們設w i 表示第1 i個月的總收入與第1 fa i 1 個月的總收入之差,及第fa i i個月的總收入。如圖。若i 1,j在同乙個集合中,則第i j個月的總收入為w j w i 1...

bzoj1005 hnoi2008 明明的煩惱

time limit 1 sec memory limit 162 mb submit 3157 solved 1262 submit status discuss 自從明明學了樹的結構,就對奇怪的樹產生了興趣.給出標號為1到n的點,以及某些點最終的度數,允許在任意兩點間連線,可產生多少棵度數滿足要...

BZOJ 1005 HNOI2008 明明的煩惱

給定一棵n個節點的樹的節點的度數,其中一些度數無限制,求可以生成多少種樹。用到了prufer數列的知識。度娘 prufer數列 是由有乙個對於頂點標過號的樹 標號樹 轉化來的數列,點數為n的樹轉化來的prufer數列長度為n 2。由heinz prufer於1918年在證明cayley定理時首次提出...