JSOI2018 潜入行动

题目链接

参考题解

Solution

注意题面:在当前节点设置监听设备不能监听到节点本身。那么节点能否被覆盖和节点是否设置监听设备需要分开设。

(f_{i,j,0/1,0/1}) 表示以第 (i) 个节点为根的子树,除了 (i) 以外的节点都已经被覆盖,(i) 号节点有没有设置监听设备、有没有被覆盖的方案数。

转移方程:

[f_{i,j+k,0,0}= sum f_{i,j,0,0} * f_{v,k,0,1} ]

[f_{i,j+k,0,1}= sum f_{i,j,0,1} * (f_{v,k,0,1} + f_{v,k,1,1}) + f_{i,j,0,0} * f_{v,k,1,1} ]

[f_{i,j+k,1,0}= sum f_{i,j,1,0} * (f_{v,k,0,0} + f_{v,k,0,1}) ]

[f_{i,j+k,1,1}= sum f_{i,j,1,0} * (f_{v,k,1,0} + f_{v,k,1,1}) + f_{i,j,1,1} * (f_{i-1,j,0,0} + f_{i-1,j,0,1} + f_{i-1,j,1,0} + f_{i-1,j,1,1}) ]

dp 过程中为了防止 f 值改变造成答案混乱,在 dp 之前用 g 数组记录一下 f 数组的初值即可。

注意:本题卡空间,f 数组需要定义为 int,在 dp 时再强转为 long long。以及,取膜的时候不要 + mod,会炸掉的,具体为什么我也不知道 qwq

Code

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define Rint register int 
#define LL long long
using namespace std;

const int N = 100010, mod = 1000000007;
struct edge { int nxt, to; } e[N << 1];
int n, K, cnt = 0, siz[N], head[N], f[N][110][2][2], g[110][2][2];

void add(int x, int y) { e[++cnt] = (edge) { head[x], y }; head[x] = cnt; }
int Mod(LL x, LL y) { x %= mod, y %= mod; return (int)(x + y + mod) % mod; }

void dfs(int x, int fa)
{
    siz[x] = 1;
    f[x][0][0][0] = f[x][1][1][0] = 1;
    for(int i = head[x]; i; i = e[i].nxt)
    {
        int v = e[i].to;
        if(v == fa) continue;
        dfs(v, x);
        for(Rint j = 0; j <= min(siz[x], K); j++)
        {
            g[j][0][0] = f[x][j][0][0],f[x][j][0][0] = 0;
            g[j][0][1] = f[x][j][0][1],f[x][j][0][1] = 0;
            g[j][1][0] = f[x][j][1][0],f[x][j][1][0] = 0;
            g[j][1][1] = f[x][j][1][1],f[x][j][1][1] = 0;
        }
        for(Rint j = 0; j <= min(siz[x], K); j++)
        {
            for(Rint k = 0; k <= min(siz[v], K - j); k++)
            {
                f[x][j + k][0][0] = Mod((LL)f[x][j + k][0][0],(LL)g[j][0][0] * (LL)f[v][k][0][1]);
                f[x][j + k][0][1] = Mod((LL)f[x][j + k][0][1],(LL)g[j][0][0] * (LL)f[v][k][1][1] + (LL)g[j][0][1] * ((LL)f[v][k][1][1] + (LL)f[v][k][0][1]));
                f[x][j + k][1][0] = Mod((LL)f[x][j + k][1][0],(LL)g[j][1][0] * ((LL)f[v][k][0][0] + (LL)f[v][k][0][1]));
                f[x][j + k][1][1] = Mod((LL)f[x][j + k][1][1],(LL)g[j][1][0] * ((LL)f[v][k][1][0] + (LL)f[v][k][1][1]) + (LL)g[j][1][1] * ((LL)f[v][k][0][0] + (LL)f[v][k][0][1] + (LL)f[v][k][1][0] + (LL)f[v][k][1][1]));
            }
        }
        siz[x] += siz[v];
    }
}

int main()
{
    scanf("%d%d", &n, &K);
    memset(head, 0, sizeof(head));
    for(int u, v, i = 1; i < n; i++)
        scanf("%d%d", &u, &v), add(u, v), add(v, u);
    dfs(1, 0);
    printf("%d", (int)(f[1][K][0][1] + f[1][K][1][1]) % mod);
    return 0;
}
原文地址:https://www.cnblogs.com/Andy-park/p/13777121.html