[JSOI2018] 潜入行动

发布时间 2023-08-26 17:04:29作者: Ciaxin

题目描述

外星人又双叒叕要攻打地球了,外星母舰已经向地球航行!这一次,JYY 已经联系好了黄金舰队,打算联合所有 JSOIer 抵御外星人的进攻。

在黄金舰队就位之前,JYY 打算事先了解外星人的进攻计划。现在,携带了监听设备的特工已经秘密潜入了外星人的母舰,准备对外星人的通信实施监听。

外星人的母舰可以看成是一棵 \(n\) 个节点、 \(n-1\) 条边的无向树,树上的节点用 \(1,2,\cdots,n\) 编号。JYY 的特工已经装备了隐形模块,可以在外星人母舰中不受限制地活动,可以神不知鬼不觉地在节点上安装监听设备。

如果在节点 \(u\) 上安装监听设备,则 JYY 能够监听与 \(u\) 直接相邻所有的节点的通信。换言之,如果在节点 \(u\) 安装监听设备,则对于树中每一条边 \((u,v)\) ,节点 \(v\) 都会被监听。特别注意放置在节点 \(u\) 的监听设备并不监听 \(u\) 本身的通信,这是 JYY 特别为了防止外星人察觉部署的战术。

JYY 的特工一共携带了 \(k\) 个监听设备,现在 JYY 想知道,有多少种不同的放置监听设备的方法,能够使得母舰上所有节点的通信都被监听?为了避免浪费,每个节点至多只能安装一个监听设备,且监听设备必须被用完

code

#include <bits/stdc++.h>
using namespace std;

inline int read()
{
    int x = 0; char c = getchar();
    while (! isdigit(c)) c = getchar();
    while (isdigit(c)) 
        x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
    return x;
}

const int mod = 1e9 + 7;
const int Maxn = 1e5 + 7;

vector<int> g[Maxn];
int n, k, dp[Maxn][101][4], tmp[101][4];
int siz[Maxn];

/* 
 * 令f[i][j][0~3]为以i为根节点的子树内,放了j个设备;
 * 0表示为本身没放,当前节点没有覆盖;
 * 1表示为本身放,当前节点没有覆盖;
 * 2表示为本身没放,当前节点有覆盖;
 * 3表示为本身放,当前节点有覆盖的方案数。
 * 
 * f[u][i + j][0] = f[u][i][0] * f[v][j][2]
 * f[u][i + j][1] = f[u][i][1] * (f[v][j][0] + f[v][j][2])
 * f[u][i + j][2] = f[u][i][2] * (f[v][j][2] + f[v][j][3]) + f[u][i][0] * f[v][j][3]
 * f[u][i + j][3] = f[u][i][1] * (f[v][j][1] + f[v][j][3]) + f[u][i][3] * f[v][j][0~3]
 */

void dfs(int u, int fa)
{
    siz[u] = 1;
    dp[u][0][0] = dp[u][1][1] = 1;  
    for (int v : g[u]) if (v != fa)
    {
        dfs(v, u);
        for (int i = 0; i <= k; i ++ ) 
            for (int j = 0; j <= 3; j ++ )
                tmp[i][j] = 0;
        
        for (int i = 0; i <= min(siz[u], k); i ++ ) 
            for (int j = 0; j <= min(siz[v], k - i); j ++ ) 
            {
                tmp[i + j][0] = (1ll * dp[u][i][0] * dp[v][j][2] %mod + tmp[i + j][0]) %mod;

                tmp[i + j][1] = (1ll * dp[u][i][1] * (1ll * dp[v][j][0] + 1ll * dp[v][j][2]) %mod + tmp[i + j][1]) %mod;

                tmp[i + j][2] = (1ll * dp[u][i][2] * (1ll * dp[v][j][2] + 1ll * dp[v][j][3]) %mod + tmp[i + j][2]) %mod;
                tmp[i + j][2] = (1ll * dp[u][i][0] * dp[v][j][3] %mod + tmp[i + j][2]) %mod;

                tmp[i + j][3] = (1ll * dp[u][i][3] * (1ll * dp[v][j][0] + 1ll * dp[v][j][1] + 1ll * dp[v][j][2] + dp[v][j][3]) %mod + tmp[i + j][3]) %mod;
                tmp[i + j][3] = (1ll * dp[u][i][1] * (1ll * dp[v][j][1] + dp[v][j][3]) %mod + tmp[i + j][3]) %mod;
            }
        siz[u] += siz[v];

        for (int i = 0; i <= k; i ++ )
            for (int j = 0; j <= 3; j ++ ) 
                dp[u][i][j] = tmp[i][j];
    }
}

int main()
{
    n = read(); k = read();
    for (int i = 1, u, v; i < n; i ++ ) 
    {   
        u = read(), v = read();
        g[u].push_back(v); g[v].push_back(u);
    }
    dfs(1, 0);
    printf("%lld", (dp[1][k][2] + dp[1][k][3]) %mod);
    return 0;
}