BZOJ2314 士兵的放置

树形DP,恩然后就不会了。。。

先写了个错的离谱程序。。。果然WA了

然后开始乱搞,欸,对了!

令f[i], g[i], h[i]分别表示i号节点自己放士兵,被儿子上的士兵控制,不被儿子上的士兵控制但被父亲上的士兵控制的情况下,以i为子树中最少的士兵数

F[i], G[i], H[i]表示对应的方案数,然后这方程写的沁人心脾。。。看程序吧

 1 /**************************************************************
 2     Problem: 2314
 3     User: rausen
 4     Language: C++
 5     Result: Accepted
 6     Time:3224 ms
 7     Memory:99512 kb
 8 ****************************************************************/
 9
10 #include <cstdio>
11 #include <algorithm>
12
13 using namespace std;
14 typedef long long ll;
15 const int N = 5e5 + 5;
16 const int inf = 1e9;
17 const int mod = 1032992941;
18 const int Maxlen = N * 15;
19
20 struct edge {
21     int next, to;
22     edge() {}
23     edge(int _n, int _t) : next(_n), to(_t) {}
24 } e[N << 1];
25
26 int n;
27 int first[N], tot;
28 ll f[N], g[N], h[N];
29 ll F[N], G[N], H[N];
30 ll ans;
31 bool vis[N];
32 char buf[Maxlen], *c = buf;
33 int Len;
34
35 inline int read() {
36     int x = 0;
37     while (*c < ‘0‘ || ‘9‘ < *c) ++c;
38     while (‘0‘ <= *c && *c <= ‘9‘)
39         x = x * 10 + *c - ‘0‘, ++c;
40     return x;
41 }
42
43 inline void Add_Edges(int x, int y) {
44     e[++tot] = edge(first[x], y), first[x] = tot;
45     e[++tot] = edge(first[y], x), first[y] = tot;
46 }
47
48 #define y e[x].to
49 void dfs(int p) {
50     int x, mn;
51     ll t;
52     vis[p] = 1;
53     f[p] = 1, g[p] = inf, h[p] = 0;
54     F[p] = G[p] = H[p] = 1;
55     for (x = first[p]; x; x = e[x].next)
56         if (!vis[y]) {
57             dfs(y);
58
59             mn = min(min(f[y], g[y]), h[y]), t = 0;
60             if (f[y] == mn) t += F[y];
61             if (g[y] == mn) t += G[y];
62             if (h[y] == mn) t += H[y];
63             f[p] += mn, (F[p] *= t) %= mod;
64
65             mn = min(min(g[p] + f[y], g[p] + g[y]), h[p] + f[y]), t = 0;
66             if (g[p] + f[y] == mn) t += G[p] * F[y];
67             if (g[p] + g[y] == mn) t += G[p] * G[y];
68             if (h[p] + f[y] == mn) t += H[p] * F[y];
69             g[p] = mn, G[p] = t % mod;
70
71             h[p] += g[y], (H[p] *= G[y]) %= mod;
72         }
73 }
74 #undef y
75
76 int main() {
77     Len = fread(c, 1, Maxlen, stdin);
78     buf[Len] = ‘\0‘;
79     int i, x, y;
80     n = read();
81     for (i = 1; i < n; ++i) {
82         x = read(), y = read();
83         Add_Edges(x, y);
84     }
85     dfs(1);
86     printf("%lld\n", min(f[1], g[1]));
87     printf("%lld\n", f[1] == g[1] ? (F[1] + G[1]) % mod : f[1] < g[1] ? F[1] : G[1]);
88     return 0;
89 }

时间: 2024-12-28 02:33:48

BZOJ2314 士兵的放置的相关文章

bzoj2314: 士兵的放置(树形DP)

0表示被父亲控制,1表示被儿子控制,2表示被自己控制.f表示最少士兵数,g表示方案数. 转移贼难写,写了好久之后写不下去了,看了一眼题解,学习了...原来还可以这么搞 比如求f[i][1]的时候,要在所有儿子里选一个儿子的f[to][2]来转移,这有一个非常巧妙的做法,那就是从自己转移... 每次可以选择从f[i][1]+min(f[to][1], f[to][2])转移或者从f[i][0]+f[to][2]转移,并使得f[i][1]比f[i][0]先转移,这样的话相当于每次会从第一次取f[to

【BZOJ2314】士兵的放置 树形DP

[BZOJ2314]士兵的放置 Description 八中有N个房间和N-1双向通道,任意两个房间均可到达.现在出了一件极BT的事,就是八中开始闹鬼了.老大决定加强安保,现在如果在某个房间中放一个士兵,则这个房间以及所有与这个房间相连的房间都会被控制.现在 老大想知道至少要多少士兵可以控制所有房间.以及有多少种不同的方案数. Input 第一行一个数字N,代表有N个房间,房间编号从1开始到N.N<=500000,下面将有N-1行,每行两个数,代表这两个房间相连. Output 第一行输出至少有

BZOJ 2314: 士兵的放置( 树形dp )

树形dp... dp(x, 0)表示结点x不放士兵, 由父亲控制: dp(x, 1)表示结点x不放士兵, 由儿子控制: dp(x, 2)表示结点x放士兵. ------------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> using namespace st

BZOJ 2314 士兵的放置(play) 树形DP

题目大意:给定一棵树,求最小支配集以及最小支配集数量 首先我们需要会求最小支配集- - 其实支配集的求法很优雅的= = 那些第一问就写了一大坨的第二问还怎么写- - 可以自己YY一下简单的支配集求法= = 实在不懂看代码吧我懒得解释了= = 然后第二问就直接把方案数顺便统计下就行了 大半夜胡乱写了发居然也过了= = #include <cstdio> #include <cstring> #include <iostream> #include <algorith

BZOJ 1458 士兵占领 Dinic最大流

题目大意:给定一个m*n的棋盘,其中k个点有障碍,要求放置最少的士兵,使第i行有至少L[i]个,第j列有至少C[j]个 首先这种问题很明显的网络流 但是正图肯定是跑不了 限制条件是至少而且要求放置的也是最少 很难解决 反向考虑 将棋盘上先放满士兵 此时若不能满足条件则无解 然后求最多能撤掉多少个士兵 其中第i行最多撤去templ[i]-l[i]个士兵 templ[i]表示第i行当前放置的士兵个数 尼玛我的网络流是多久不写了--居然没连反向弧就跑样例--最逗的是数组开小一倍不报RE报WA-- #i

【bzoj1458】士兵占领

Description 有一个M * N的棋盘,有的格子是障碍.现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵.我们称这些士兵占领了整个棋盘当满足第i行至少放置了Li个士兵, 第j列至少放置了Cj个士兵.现在你的任务是要求使用最少个数的士兵来占领整个棋盘. Input 第一行两个数M, N, K分别表示棋盘的行数,列数以及障碍的个数. 第二行有M个数表示Li. 第三行有N个数表示Ci. 接下来有K行,每行两个数X, Y表示(X, Y)这个格子是障碍. O

bzoj1458 士兵占据

1458: 士兵占据 Time Limit: 10 Sec  Memory Limit: 64 MB Submit: 685  Solved: 398 [Submit][Status][id=1458" style="color:blue; text-decoration:none">Discuss] Description 有一个M * N的棋盘,有的格子是障碍.如今你要选择一些格子来放置一些士兵,一个格子里最多能够放置一个士兵,障碍格里不能放置士兵.我们称这些士兵占

[BZOJ 1458]士兵占领(网络流)

Description 有一个M * N的棋盘,有的格子是障碍.现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵.我们称这些士兵占领了整个棋盘当满足第i行至少放置了Li个士兵, 第j列至少放置了Cj个士兵.现在你的任务是要求使用最少个数的士兵来占领整个棋盘. Solution 可以用上下界最小流来做,不过我觉得黄学长的这个思路也很直接 将每行每列都看成一个点,由s向行连边,容量为可以放置的士兵数-至少放置的士兵数 由列向t连边,容量为可以放置的士兵数-至少

1458: 士兵占领

1458: 士兵占领 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1044  Solved: 598[Submit][Status][Discuss] Description 有一个M * N的棋盘,有的格子是障碍.现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵.我们称这些士兵占领了整个棋盘当满足第i行至少放置了Li个士兵, 第j列至少放置了Cj个士兵.现在你的任务是要求使用最少个数的士兵来占领整个棋盘.