zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    嵌入式C语言编程小技巧
    冒号:在linux bash中的各种用法
    巧用ls命令
    嵌入式C精华提炼1
    不知道这些,别说你是嵌入式工程师!
    这些ARM基础知识你还不知道吗
    代码示例_C_冒泡
    代码示例_文件IO_lseek
    代码示例_文件IO_read / write
    代码示例_标准IO_fseek
  • 原文地址:https://www.cnblogs.com/Andy-park/p/13777121.html
Copyright © 2011-2022 走看看