BZOJ5314 JSOI2018 潜入行动

BZOJ5314 JSOI2018 潜入行动

题目描述

给你一棵树,选取k个点放一个监听器,一个监听器只能够覆盖与它相邻的点,要求所有的点都被覆盖。求方案数.

解题思路

首先要往树形dp方面去思考。

然后就是丧心病狂的分类讨论

\(f[u][i][0/1][0/1]\) 表示\(u\)子树内选了\(i\)个点,节点\(u\)是否被覆盖,是否装了一个监听器。(不要问我怎么设出来的,一开始搞了3个0/1状态的,发现可以少一个,瞎jb多试试看那个状态好分类,好转移)

这样可以把子树\(u\)分成4种,然后枚举两种合并讨论。

然而有一些情况是不能够合并的,会出现重复的情况。

比如\(00+00\) 得到的新的树不是一个合法的树,这时必须在u放一个监听器,然而这种状态会在\(01+00\)中被算到一次。要避免这种。

所以我们讨论了16种情况之后发现,如果这次要添加一个监听器,那肯定是不对的。我们要一开始就确定好这个点是否放监听器,后面就可以不用再管了,不然会重复。 稍微画画图,分个类。

关于复杂度,乍一看是\(O(nk^2)\),但是有人证明了,是\(O(nk)\)的。请务必记住结论(这个结论怎么证的反正不会考)。小心后面再次遇见这种题目。(比如昨天的ZROI把我搞自闭了)

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 11;
const int mod = 1e9 + 7;
int n, K, sz[N];
int f[N][111][2][2], G[111][2][2], F[111][2][2], tmp[111][2][2];
int head[N], to[N<<1], nex[N<<1], size;
void add(int x, int y){
    to[++size] = y;
    nex[size] = head[x];
    head[x] = size;
}
void dfs(int u, int fa){
    f[u][0][0][0] = f[u][1][0][1] = 1;
    sz[u] = 1;
    for(int i = head[u];i;i = nex[i]){
        int v = to[i];
        if(v == fa)continue;
        dfs(v, u);
        memcpy(F, f[u], sizeof F);
        memcpy(G, f[v], sizeof F);
        for(int j = 0;j <= sz[u] && j <= K; j++){
            for(int k = 0;k <= sz[v] && j + k <= K; k++){
                for(int a = 0;a <= 1; a++){
                    for(int b = 0;b <= 1; b++){
                        (tmp[j+k][b][1] += 1LL * F[j][0][1] * G[k][a][b] % mod) %= mod;
                        (tmp[j+k][1][1] += 1LL * F[j][1][1] * G[k][a][b] % mod) %= mod;
                    }
                }
                (tmp[j+k][1][0] += (1LL * F[j][1][0] * (G[k][1][1] + G[k][1][0]) % mod)) %= mod;
                (tmp[j+k][0][0] += 1LL * F[j][0][0] * G[k][1][0] % mod) %= mod;
                (tmp[j+k][1][0] += 1LL * F[j][0][0] * G[k][1][1] % mod) %= mod;
            }
        }
        sz[u] += sz[v];
        for(int j = 0;j <= K; j++){
            for(int a = 0;a <= 1; a++){
                for(int b = 0;b <= 1; b++){
                    f[u][j][a][b] = tmp[j][a][b]; 
                    tmp[j][a][b] = 0;
                }
            }
        }
    }
    /*printf("u=%d\n", u);
    for(int i = 0;i <= K; i++){
        printf("i=%d %d %d %d %d\n", i, f[u][i][0][0], f[u][i][0][1], f[u][i][1][0], f[u][i][1][1]);
    }*/
}
int main(){
    freopen("5314.in", "r", stdin);
    freopen("5314.out", "w", stdout);
    cin>>n>>K;
    int u, v;
    for(int i = 1;i < n; i++){
        scanf("%d%d", &u, &v);
        add(u, v); add(v, u);
    }
    dfs(1, 1);
    printf("%d\n", (f[1][K][1][0] + f[1][K][1][1]) % mod);
    return 0;
}
posted @ 2020-08-04 16:02  LawrenceD  阅读(124)  评论(0)    收藏  举报