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

题目大意:给定一棵树,求最小支配集以及最小支配集数量

首先我们需要会求最小支配集- -

其实支配集的求法很优雅的= = 那些第一问就写了一大坨的第二问还怎么写- -

可以自己YY一下简单的支配集求法= = 实在不懂看代码吧我懒得解释了= =

然后第二问就直接把方案数顺便统计下就行了

大半夜胡乱写了发居然也过了= =

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 500500
#define MOD 1032992941
using namespace std;
struct abcd{
	int to,next;
}table[M<<1];
int n,fa[M];
long long f[M],g[M],h[M];
long long F[M],G[M],H[M];
//f-自己选择 g-被子节点支配 h-放置play
int head[M],tot;
void Add(int x,int y)
{
	table[++tot].to=y;
	table[tot].next=head[x];
	head[x]=tot;
}
void Tree_DP(int x)
{
	int i;
	f[x]=1;g[x]=0x3f3f3f3f;h[x]=0;
	F[x]=G[x]=H[x]=1;
	for(i=head[x];i;i=table[i].next)
	{
		if(table[i].to==fa[x])
			continue;
		fa[table[i].to]=x;
		Tree_DP(table[i].to);

		{
			long long min_sta=min(min(f[table[i].to],g[table[i].to]),h[table[i].to]);
			long long ans=0;
			if(f[table[i].to]==min_sta)
				ans+=F[table[i].to];
			if(g[table[i].to]==min_sta)
				ans+=G[table[i].to];
			if(h[table[i].to]==min_sta)
				ans+=H[table[i].to];
			f[x]+=min_sta;
			F[x]=(ans*F[x])%MOD;
		}

		{
			long long min_sta=min(min(g[x]+f[table[i].to],g[x]+g[table[i].to]),h[x]+f[table[i].to]);
			long long ans=0;
			if(g[x]+f[table[i].to]==min_sta)
				ans+=(G[x]*F[table[i].to])%MOD;
			if(g[x]+g[table[i].to]==min_sta)
				ans+=(G[x]*G[table[i].to])%MOD;
			if(h[x]+f[table[i].to]==min_sta)
				ans+=(H[x]*F[table[i].to])%MOD;
			g[x]=min_sta;
			G[x]=ans%MOD;
		}

		{
			h[x]+=g[table[i].to];
			H[x]=(H[x]*G[table[i].to])%MOD;
		}

	}
}
int main()
{
	int i,x,y;
	cin>>n;
	for(i=1;i<n;i++)
	{
		scanf("%d%d",&x,&y);
		Add(x,y);Add(y,x);
	}
	Tree_DP(1);
	cout<<min(f[1],g[1])<<endl;
	cout<<( (f[1]==g[1]) ? ((F[1]+G[1])%MOD) : (f[1]<g[1]?F[1]:G[1]) )<<endl;
}
时间: 2024-10-26 06:14:07

BZOJ 2314 士兵的放置(play) 树形DP的相关文章

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

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

BZOJ 1907 树的路径覆盖 树形DP

题目大意:给定一棵树,求最小路径覆盖 数据范围1W,看到还想跑网络流来着= = 不过算了明明树形DP这么水还是不要用网络流这种大杀器为好 首先将所有的链都考虑成以链上所有点的LCA为转折点的V字形 那么点有两种:转折点和非转折点 因此我们选择两种状态进行转移:还会和父亲组成链的状态和成为转折点的状态 转移就自己YY算了 时间复杂度是线性的 #include <cstdio> #include <cstring> #include <iostream> #include

BZOJ 1509: [NOI2003]逃学的小孩( 树形dp )

树形dp求出某个点的最长3条链a,b,c(a>=b>=c), 然后以这个点为交点的最优解一定是a+2b+c.好像还有一种做法是求出树的直径然后乱搞... --------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> #include<cctype> using

bzoj 1017[JSOI2008]魔兽地图DotR - 树形dp

1017: [JSOI2008]魔兽地图DotR Time Limit: 30 Sec  Memory Limit: 162 MB Description DotR (Defense of the Robots) Allstars是一个风靡全球的魔兽地图,他的规则简单与同样流行的地图DotA (Defense of the Ancients) Allstars.DotR里面的英雄只有一个属性--力量.他们需要购买装备来提升自己的力量值,每件装备都可以使佩戴它的英雄的力量值提高固定的点数,所以英雄

BZOJ 3238: [Ahoi2013]差异 后缀自动机 树形dp

http://www.lydsy.com/JudgeOnline/problem.php?id=3238 就算是全局变量,也不要忘记,初始化(吐血). 长得一副lca样,没想到是个树形dp(小丫头还有两幅面孔呢). 看代码实现吧,不大容易口头解释,把加的和减的分开算就可以了,减去的通过倒着建sam(相当于建一棵后缀树),然后算每个len取的次数实现,注意树归中一些避免重复操作. 1 /********************************************************

bzoj 1060: [ZJOI2007]时态同步【树形dp】

可能算不上dp,大概是个树形模拟 先一遍dfs算出f[u]为每个点最深的叶子到u的距离,然后再dfs一下,ans加上f[u]-f[e[i].to]-e[i].va,f[u]-f[e[i].to]是这条边应该的用时 #include<iostream> #include<cstdio> using namespace std; const int N=500005; int n,m,cnt,f[N],h[N]; long long ans; struct qwe { int ne,t

BZOJ 1017 魔兽地图DotR(树形DP)

题意:有两类装备,高级装备A和基础装备B.现在有m的钱.每种B有一个单价和可以购买的数量上限.每个Ai可以由Ci种其他物品合成,给出Ci种其他物品每种需要的数量.每个装备有一个贡献值.求最大的贡献值.已知物品的合成路线是一个严格的树模型.即有一种物品不会合成其他任意物品,其余物品都会仅仅可用作合成另外一种物品 思路:f[i][j][k],代表第i个物品,花费了j,向上提供k个i物品. 1 #include<algorithm> 2 #include<cstdio> 3 #inclu

【BZOJ 3238】差异 后缀自动机+树形DP

题意 给定字符串,令$s_i$表示第$i$位开始的后缀,求$\sum_{1\le i < j \le n} len(s_i)+len(s_j)-2\times lcp(s_i,s_j)$ 先考虑前面的和式,直接计算为$\frac{n(n^2-1)}{2}$,考虑后面的和式,$lcp$相关可以用sam求解,sam形成的parent树是原串的前缀树,所以两个串的最长公共后缀是在parent树上最近公共祖先对应的状态的长度$maxlen_s-maxlen_{pa_s}$,将原串反向建立sam得到后缀树