題目描述
lyk有一棵樹,它想給這棵樹重標號。
重標號後,這棵樹的所有葉子節點的值為它到根的路徑上的編號最小的點的編號。
這棵樹的煩惱值為所有葉子節點的值的乘積。
lyk想讓這棵樹的煩惱值最大,你只需輸出最大煩惱值對1e9+7取模後的值就可以了。
注意一開始1號節點為根,重標號後這個節點仍然為根。
update:資料保證葉子節點個數<=20。
例如樣例中,將1,2,3,4,5重標號為4,3,1,5,2,此時原來編號為4,5的兩個葉子節點的值為3與1,這棵樹的煩惱值為3。不存在其它更優解。
input
第一行乙個數n(1<=n<=100000)。
接下來n-1行,每行兩個數ai,bi(1<=ai,bi<=n),表示存在一條邊連線這兩個點。
output
一行表示答案
input示例
51 2
2 42 3
3 5
output示例
3
非常好的一道樹形dp+狀壓dp+虛樹。
首先我們發現葉子節點一定比父節點要小,因為你要讓小得數盡量往下放(這樣影響最小),並且會發現如果子樹是一條鏈的話,那麼那麼一定是從小往上排著放,因為這條鏈上的最小值已經確定並且對其他子樹沒有影響,所以要把前幾小得數都放在這條鏈上。那麼我們發現這條鏈只與鏈的長度有關,與具體的形態無關。
所以我們可以建虛樹,所謂虛樹就是我把原樹中沒用的點或邊刪掉,重新建一顆有用的樹,這是一種思想,只保留有用 的邊和點,像krustra重構樹也是這樣。
我們再接著看資料範圍葉子節點數才20,像這麼小的數(<=20),一定要往狀壓dp上想。到此題目考慮完畢,基本的演算法已經想出來了,下面就是具體實現了。
首先是虛樹怎麼建,前面已經說了一條鏈的情況是沒有什麼用的,所以可以刪掉。那麼我們只需要儲存葉子節點和子節點大於1的節點。建完新樹之後,我們要算一下每個節點下的葉子個數(size),還要記一下實際選了哪些葉子(got陣列),如果實際的個數=有的個數,那麼我們就可以把當前算到的編號加上這個點以上省略點的個數。狀態轉移就是直接列舉其他沒選的葉子是不是選就行了。
還有一處細節,由於取模之後沒辦法比較大小,所以要用乙個double型別的存大小,(long long 存不下)。
#include#include#include#include#includetypedef long long ll;
using namespace std;
const int mod=1e9+7;
const int n=100010;
int pre[n*2],last[n],other[n*2],num;
bool gg[n],leaf[n];
int len[n],leaf_pos[210],cnt,leafnum,size[n],got[210];
vectorvec[210];
double f[(1<<20)+n];
int g[(1<<20)+n];
inline void add(int x,int y)
void dfs(int x,int fa)
} leaf[x]=(son==0);
if(son==1) gg[x]=1;
}void dfs1(int x,int fa,int _fa,int tmplen)
int v;
for(int i=last[x];i;i=pre[i]) if((v=other[i])!=fa) dfs1(v,x,_fa,tmplen);
}int main()
} printf("%d\n",g[st-1]);
return 0;
}
51nod 1673 樹有幾多愁
lyk有一棵樹,它想給這棵樹重標號。重標號後,這棵樹的所有葉子節點的值為它到根的路徑上的編號最小的點的編號。這棵樹的煩惱值為所有葉子節點的值的乘積。lyk想讓這棵樹的煩惱值最大,你只需輸出最大煩惱值對1e9 7取模後的值就可以了。注意一開始1號節點為根,重標號後這個節點仍然為根。資料保證葉子節點個數...
51nod1673 樹有幾多愁(狀壓DP)
傳送門 lyk有一棵樹,它想給這棵樹重標號。重標號後,這棵樹的所有葉子節點的值為它到根的路徑上的編號最小的點的編號。這棵樹的煩惱值為所有葉子節點的值的乘積。lyk想讓這棵樹的煩惱值最大,你只需輸出最大煩惱值對1e9 7取模後的值就可以了。注意一開始1號節點為根,重標號後這個節點仍然為根。資料保證葉子...
51nod1462 樹據結構
給一顆以1為根的樹。每個點有兩個權值 vi,ti,一開始全部是零。q次操作 讀入o,u,d o 1 對u到根上所有點的vi d o 2 對u到根上所有點的ti vi d 最後,輸出每個點的ti值 n,q 100000 有50 的資料n,q 10000 注 所有數64位整數不會爆。我們考慮用樹剖來做這...