• [JLOI2016/SHOI2016]侦察守卫


    嘟嘟嘟

    这道题可以说是[HNOI2003]消防局的设立的升级版。距离从2改为了d。

    辛亏d只有20,这也就是一个切入点。

    令f[u][j]表示u四周 j - 1的距离需要被覆盖,g[u][j]表示u可以像四周覆盖 j 的距离。

    考虑转移方程,令v为u的其中一个儿子:

    1.f[u][j]:直接从v延伸而来:f[u][j] = Σ f[v][j - 1]

    2.g[u][j]:用前几个儿子已经得出的g[u][j]去覆盖v:g[u][j] = g[u][j] + f[v][j];或者用v覆盖u:g[now][j] = f[now][j +1] +g[v][j + 1],所以g[now][j] = min{g[now][j] + f[v][j], f[now][j + 1] + g[v][j + 1]}.

    对于f,可能距离小的比大的还优,所以还要再求一遍前缀最小值:f[now][j] = min{f[now][k]} (0 <= k < j)

    同理对于g,可能覆盖距离大的比距离小的还优,所以后缀最小值:g[now][j] = min{g[now][k]} (j < k <= d)

    最后考虑的是初值:显然g[now][j] = c[now] (1 <= j <= d)。然后如果这个点B神可能出现,f[now][0] = g[now][0] = c[now],表示这个点需要覆盖。

     (代码折叠坏啦)

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cmath>
     4 #include<algorithm>
     5 #include<cstring>
     6 #include<cstdlib>
     7 #include<cctype>
     8 #include<vector>
     9 #include<stack>
    10 #include<queue>
    11 using namespace std;
    12 #define enter puts("") 
    13 #define space putchar(' ')
    14 #define Mem(a, x) memset(a, x, sizeof(a))
    15 #define rg register
    16 typedef long long ll;
    17 typedef double db;
    18 const int INF = 0x3f3f3f3f;
    19 const db eps = 1e-8;
    20 const int maxn = 5e5 + 5;
    21 inline ll read()
    22 {
    23     ll ans = 0;
    24     char ch = getchar(), last = ' ';
    25     while(!isdigit(ch)) {last = ch; ch = getchar();}
    26     while(isdigit(ch)) {ans = (ans << 1) + (ans << 3) + ch - '0'; ch = getchar();}
    27     if(last == '-') ans = -ans;
    28     return ans;
    29 }
    30 inline void write(ll x)
    31 {
    32     if(x < 0) x = -x, putchar('-');
    33     if(x >= 10) write(x / 10);
    34     putchar(x % 10 + '0');
    35 }
    36 
    37 int n, d, m, c[maxn];
    38 bool vis[maxn];
    39 
    40 struct Edge
    41 {
    42     int nxt, to;
    43 }e[maxn << 1];
    44 int head[maxn], ecnt = -1;
    45 void addEdge(int x, int y)
    46 {
    47     e[++ecnt] = (Edge){head[x], y};
    48     head[x] = ecnt;
    49 }
    50 
    51 int f[maxn][22], g[maxn][22];
    52 void dfs(int now, int _f)
    53 {
    54     for(int i = 1; i <= d; ++i) g[now][i] = c[now];
    55     if(vis[now]) f[now][0] = g[now][0] = c[now];
    56     g[now][d + 1] = INF;
    57     for(int i = head[now], v; i != -1; i = e[i].nxt)
    58     {
    59         v = e[i].to;
    60         if(v == _f) continue;
    61         dfs(v, now);
    62         for(int j = d; j >= 0; --j) g[now][j] = min(g[now][j] + f[v][j], f[now][j + 1] + g[v][j + 1]);
    63         for(int j = d; j >= 0; --j) g[now][j] = min(g[now][j], g[now][j + 1]);
    64         f[now][0] = g[now][0];
    65         for(int j = 1; j <= d; ++j) f[now][j] += f[v][j - 1];
    66         for(int j = 1; j <= d; ++j) f[now][j] = min(f[now][j], f[now][j - 1]);
    67     }
    68 }
    69 
    70 int main()
    71 {
    72     Mem(head, -1);
    73     n = read(); d = read();
    74     for(int i = 1; i <= n; ++i) c[i] = read();
    75     m = read();
    76     for(int i = 1; i <= m; ++i) {int x = read(); vis[x] = 1;}
    77     for(int i = 1; i < n; ++i)
    78     {
    79         int x = read(), y = read();
    80         addEdge(x, y); addEdge(y, x);
    81     }
    82     dfs(1, 0);
    83     write(f[1][0]), enter;
    84     return 0;
    85 }
  • 相关阅读:
    关于git的文件内容冲突解决
    【C++】 四种强制类型转换(static_cast 与 dynamic_cast 的区别!)
    如何判断一个变量是不是指针
    类型识别
    C++中的异常处理(下)
    C++中的异常处理(中)
    C++中的异常处理(上)
    C语言异常处理
    用Zebra打造Linux下小型路由器
    Linux下PortSentry的配置
  • 原文地址:https://www.cnblogs.com/mrclr/p/9907146.html
Copyright © 2020-2023  润新知