【East!模拟赛】【Round1】【BZOJ1017】魔兽地图Dotr 树形DP

题意不多说。

曰:

呃,首先显然这是一个树形DP。

然后我不会什么高大上的算法,我只能提供一种非常慢,但是能在BZ切的算法(因为是总时限并且还有O2)。

题解:

不需要新建树,这个树就行。

首先这道题一眼就能想到树形背包。。但是树形背包怎么做呢?

因为需要合成,所以这里的状态F[i][j][k]并不是i节点有j个花费为k时的最大收益,而是i节点给其父亲j个花费k时的最大收益(不含父亲收益)。好吧,这个我自己没想出来,但是或许我可以给你讲讲怎么想出来。

我们考虑这道题有两个难点:

第一个是怎么确定父亲买多少个,第二个是怎么保证所有子节点都贡献了这么多个。。

其实我们不用想太多,这种题我们可以在时间复杂度尽量允许的前提下暴力一些,然后剪枝。

当然,这道题我并没有剪枝。

---------废话说了好多。

我们想到父亲需要占用一些子节点,那么子节点的状态中一定就有跟个数相关的内容,所以我们可以记录低级物品有j个的状态,可以这样一来我们枚举需要多少个,然后?好吧,没有然后了,即便是暴力,这也太暴力了。

所以想到能不能记录父亲有多少个呢?那么就有了F[i][j][k]为i节点给其父亲j个花费k时的最大收益(不含父亲收益)的状态。

而枚举父亲有多少个的时候只需要加这个东西就行了。

但是又出现了一个问题,就是枚举到父亲i个时需要每一种物品都有i个贡献,这个很难处理。

这里就涉及到了一个小技巧:for循环每到一个子节点时都记录当前父亲的状态,然后f清成-1,这时再更新。

有点累,不想细说了。。自己看代码应该可以领悟(-1的意义、最终价格的正确性两点)。

好了,说完了。

贴代码。

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 60
#define P 110
#define M 2010
#define inf 0x3f3f3f3f
using namespace std;
struct KSD
{
	int v,len,next;
}e[N];
int head[N],cnt;
void add(int u,int v,int len)
{
	++cnt;
	e[cnt].v=v;
	e[cnt].len=len;
	e[cnt].next=head[u];
	head[u]=cnt;
}
int n,m,root,ans;
int f[N][P][M],g[M];
int strength[N],cost[N],num[N];

bool in[N],out[N];
char opt;

void Tree_DP(int x)
{
	int i,j,k,v,temp;
	if(!out[x])
	{
		num[x]=min(num[x],m/cost[x]);
		for(i=0;i<=num[x];i++)
			for(j=i;j<=num[x];j++)
				f[x][i][j*cost[x]]=(j-i)*strength[x];
		return ;
	}
	num[x]=inf;
	for(i=head[x];i;i=e[i].next)
	{
		v=e[i].v;
		Tree_DP(v);
		num[x]=min(num[x],num[v]/e[i].len);
	}
	for(i=0;i<=num[x];i++)f[x][i][0]=0;
	for(i=head[x];i;i=e[i].next)
	{
		v=e[i].v;
		for(j=0;j<=num[x];j++)
		{
			memcpy(g,f[x][j],sizeof(f[x][j]));
			memset(f[x][j],-1,sizeof(f[x][j]));
			for(k=m;k>=0;k--)
			{
				for(temp=k;temp>=0;temp--)
					if(g[k-temp]+1&&f[v][j*e[i].len][temp]+1)
						f[x][j][k]=max(f[x][j][k],g[k-temp]+f[v][j*e[i].len][temp]);
			}
		}
	}
	for(i=0;i<=num[x];i++)
		for(j=i;j<=num[x];j++)
			for(k=0;k<=m;k++)
				if(f[x][j][k]+1)
					f[x][i][k]=max(f[x][i][k],f[x][j][k]+(j-i)*strength[x]),
					ans=max(ans,f[x][i][k]);
	return ;
}

int main()
{
	freopen("C.in","r",stdin);
	freopen("C.out","w",stdout);
	int i,j,k;
	int a,b;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++)
	{
		scanf("%d %s",&strength[i],&opt);
		if(opt=='A')
		{
			scanf("%d",&k);
			for(j=1;j<=k;j++)
			{
				scanf("%d%d",&a,&b);
				add(i,a,b);
				in[a]=1;
				out[i]=1;
			}
		}
		if(opt=='B')scanf("%d%d",&cost[i],&num[i]);
	}
	memset(f,-1,sizeof(f));
	for(i=1;i<=n;i++)if(!in[i]){root=i;break;}
	Tree_DP(root);
	printf("%d\n",ans);

	fclose(stdin);
	fclose(stdout);
	return 0;
}
时间: 2024-10-13 15:56:54

【East!模拟赛】【Round1】【BZOJ1017】魔兽地图Dotr 树形DP的相关文章

[JSOI2008][BZOJ1017] 魔兽地图DotR|树形动规

1017: [JSOI2008]魔兽地图DotR Time Limit: 30 Sec  Memory Limit: 162 MBSubmit: 1254  Solved: 537[Submit][Status][Discuss] Description DotR (Defense of the Robots) Allstars是一个风靡全球的魔兽地图,他的规则简单与同样流行的地图DotA (Defense of the Ancients) Allstars.DotR里面的英雄只有一个属性——力

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 [JSOI2008]魔兽地图DotR

1017: [JSOI2008]魔兽地图DotR Time Limit: 30 Sec  Memory Limit: 162 MBSubmit: 1243  Solved: 532[Submit][Status][Discuss] Description DotR (Defense of the Robots) Allstars是一个风靡全球的魔兽地图,他的规则简单与同样流行的地图DotA (Defense of the Ancients) Allstars.DotR里面的英雄只有一个属性——力

【BZOJ 1017】 [JSOI2008]魔兽地图DotR

1017: [JSOI2008]魔兽地图DotR Time Limit: 30 Sec  Memory Limit: 162 MB Submit: 1069  Solved: 433 [Submit][Status] Description DotR (Defense of the Robots) Allstars是一个风靡全球的魔兽地图,他的规则简单与同样流行的地图DotA (Defense of the Ancients) Allstars.DotR里面的英雄只有一个属性--力量.他们需要购

[BZOJ 1017][JSOI2008]魔兽地图DotR(树形Dp)

Description DotR (Defense of the Robots) Allstars是一个风靡全球的魔兽地图,他的规则简单与同样流行的地图DotA (Defense of the Ancients) Allstars.DotR里面的英雄只有一个属性——力量.他们需要购买装备来提升自己的 力量值,每件装备都可以使佩戴它的英雄的力量值提高固定的点数,所以英雄的力量值等于它购买的所有装备的力 量值之和.装备分为基本装备和高级装备两种.基本装备可以直接从商店里面用金币购买,而高级装备需要用

2016 CCPC 网络赛 B 高斯消元 C 树形dp(待补) G 状压dp+容斥(待补) H 计算几何

2016 CCPC 网络赛 A - A water problem 水题,但读题有个坑,输入数字长度很大.. B - Zhu and 772002 题意:给出n个数(给出的每个数的质因子最大不超过2000),选出多个数相乘得b.问有多少种选法让b 为完全平方数. tags:高斯消元,求异或方程组解的个数.   好题 每个数先素数分解开.  对于2000以内的每个素数p[i],这n个数有奇数个p[i]则系数为1,偶数个则系数为0,最后n个数的p[i]系数异或和都要为0才会使得最后的积为完全平方数.

BZOJ1017: [JSOI2008]魔兽地图DotR

传送门 设$f[i][j][k]$表示对于第$i$个点,向父节点贡献$j$个已合成的装备,花费了$k$的代价,最多获得的力量值. 单纯的$f[i][j][k]$是很难转移的,主要原因是无法维护和其他儿子的关系.所以对于每个节点再搞一个$g[i][j]$表示当前点的前$i$个儿子花费为$k$可以获得的最大的力量值. 然后肯定要先更新$g[][]$再以$g[][]$来更新$f[][][]$. 列出$g[i][j]$的状态转移方程就是: $g[cnt][k]=max \{ f[son][tol \ti

【East!模拟赛】【Round1】【codeforces455B】题解。

A:codeforces Round#260 div1 B [a lot of games]. 题解:俩人玩游戏,有若干个字符串,每一轮都是俩人轮流念一个字母,使得当前的这些字母是其中一个字符串或者其前缀,即在字典树上走,每人走一步,走不了的人输,然后有m轮,每轮输的下一轮先手,问最后一轮谁赢? 题解: 显然这是一道博弈题,但是如果我们单纯地计算每一局是先手赢还是后手赢,那就要跪了. 因为:先手可以选择输,以保证下一局的先手,然后一直先手,最后一局再选择赢!!! 那么我们就需要多判断几种状态.

【East!模拟赛】【Round1】【BZOJ2324】营救皮卡丘 有下界的费用流

题意:不多说了. 题解: begin 首先想到:我们要强制走过那些下界. 怎么强制呢?我们把费用赋为-inf!!看他走不走! 然后费用的初值就需要把这些扣掉的inf加回来. end. 贴代码: #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N 500 #define M 201000 #d