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個的方案數。
設表示 的子樹內安了 個監聽器, 處是否安了監聽器,是否被監聽,直接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;
}