1. 程式人生 > >bzoj5314: [Jsoi2018]潛入行動【樹形dp】

bzoj5314: [Jsoi2018]潛入行動【樹形dp】

Description

外星人又雙叒叕要攻打地球了,外星母艦已經向地球航行!這一次,JYY已經聯絡好了黃金艦隊,打算聯合所有JSO
Ier抵禦外星人的進攻。在黃金艦隊就位之前,JYY打算事先了解外星人的進攻計劃。現在,攜帶了監聽裝置的特工
已經祕密潛入了外星人的母艦,準備對外星人的通訊實施監聽。外星人的母艦可以看成是一棵n個節點、n-1條邊的
無向樹,樹上的節點用1,2…n編號。JYY的特工已經裝備了隱形模組,可以在外星人母艦中不受限制地活動,可以
神不知鬼不覺地在節點上安裝監聽裝置。如果在節點u安裝監聽裝置,則JYY能夠監聽與u直接相鄰所有的節點的通
信。換言之,如果在節點u安裝監聽裝置,則對於樹中每一條邊(u,v),節點v都會被監聽。特別注意放置在節點u的
監聽裝置並不監聽u本身的通訊,這是JYY特別為了防止外星人察覺部署的戰術。
JYY的特工一共攜帶了k個監聽裝置,現在JYY想知道,有多少種不同的放置監聽裝置的方法,能夠使得母艦上所有
節點的通訊都被監聽?為了避免浪費,每個節點至多隻能安裝一個監聽裝置,且監聽裝置必須被用完。

Input

輸入第一行包含兩個整數n,k,表示母艦節點的數量n和監聽裝置的數量k。
接下來n-1行,每行兩個整數u,v(1≤u,v≤n),表示樹中的一條邊。
1≤n≤10^5,1≤k≤min{n,100}

Output

輸出一行,表示滿足條件的方案數。
因為答案可能很大,你只需要輸出答案mod 1,000,000,007的餘數即可

Sample Input

5 3

1 2

2 3

3 4

4 5

Sample Output

1

樣例解釋

樣例資料是一條鏈

1–2–3–4–5

首先,節點 2和 4必須放置監聽裝置,否則 1,5將無法被監聽(放置的監聽裝置無法監聽它所在的節點)。剩下一

個裝置必須放置在 3號節點以同時監聽 2,4因此在 2,3,4節點放置監聽裝置是唯一合法的方案。

解題思路:

注意答案是恰好安k個的方案數。
f[i][j][0/1][0/1]表示 i 的子樹內安了 j 個監聽器,i 處是否安了監聽器,是否被監聽,直接dp即可。

#include<bits/stdc++.h>
#define ll unsigned long long
using namespace std;
int getint()
{
    int i=0,f=1;char c;
    for(c=getchar();(c!='-'
)&&(c<'0'||c>'9');c=getchar()); if(c=='-')c=getchar(),f=-1; for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0'; return i*f; } const int N=100005,mod=1e9+7; int n,K,f[N][105][2][2],size[N];ll tmp[105][2][2]; int tot,first[N],nxt[N<<1],to[N<<1]; inline void add(int &x,ll y) { x=(x+y>=mod?x+y-mod:x+y); } void Add(int x,int y) { nxt[++tot]=first[x],first[x]=tot,to[tot]=y; } void dfs(int u,int fa) { size[u]=1;f[u][0][0][0]=f[u][1][1][0]=1; for(int e=first[u];e;e=nxt[e]) { int v=to[e];if(v==fa)continue; dfs(v,u); for(int i=0,r=min(size[u],K);i<=r;i++) for(int j=0;j<=1;j++) for(int k=0;k<=1;k++) tmp[i][j][k]=f[u][i][j][k],f[u][i][j][k]=0; for(int i=0,r1=min(size[u],K);i<=r1;i++) for(int j=0,r2=min(size[v],K);i+j<=K&&j<=r2;j++) { add(f[u][i+j][0][0],tmp[i][0][0]*f[v][j][0][1]%mod); add(f[u][i+j][0][1],(tmp[i][0][0]*f[v][j][1][1]+tmp[i][0][1]*(f[v][j][0][1]+f[v][j][1][1]))%mod); add(f[u][i+j][1][0],tmp[i][1][0]*(f[v][j][0][0]+f[v][j][0][1])%mod); add(f[u][i+j][1][1],(tmp[i][1][0]*(f[v][j][1][0]+f[v][j][1][1])+tmp[i][1][1]*(f[v][j][0][0]+f[v][j][1][0])+tmp[i][1][1]*(f[v][j][0][1]+f[v][j][1][1]))%mod); } size[u]+=size[v]; } } int main() { //freopen("action.in","r",stdin); //freopen("action.out","w",stdout); n=getint(),K=getint(); for(int i=1;i<n;i++) { int x=getint(),y=getint(); Add(x,y),Add(y,x); } dfs(1,0); cout<<(f[1][K][0][1]+f[1][K][1][1])%mod<<'\n'; return 0; }