列表

详情


NC20168. [JSOI2008]魔兽地图DOTR

描述

DotR (Defense of the Robots) Allstars是一个风靡全球的魔兽地图,他的规则简单与同样流行的地图DotA (Defense of the Ancients) Allstars。
DotR里面的英雄只有一个属性——力量。他们需要购买装备来提升自己的 力量值,每件装备都可以使佩戴它的英雄的力量值提高固定的点数,所以英雄的力量值等于它购买的所有装备的力 量值之和。装备分为基本装备和高级装备两种。基本装备可以直接从商店里面用金币购买,而高级装备需要用基本装备或者较低级的高级装备来合成,合成不需要附加的金币。
装备的合成路线可以用一棵树来表示。比如,Sange and Yasha的合成需要Sange,Yasha和Sange and Yasha Recipe Scroll三样物品。其中Sange又要用Ogre Axe, Belt  of Giant Strength和 Sange Recipe Scroll合成。每件基本装备都有数量限制,这限制了你不能无限制地合成某些性价比很高的装备。
现在,英雄Spectre有M个金币,他想用这些钱购买装备使自己的力量值尽量高。你能帮帮他 吗?他会教你魔法Haunt(幽灵附体)作为回报的。

输入描述

第一行包含两个整数,N (1 ≤ n ≤ 51) 和 m (0 ≤ m ≤ 2,000)。分别表示装备的种类数和金币数。装备 用1到N的整数编号。
接下来的N行,按照装备1到装备n的顺序,每行描述一种装备。每一行的第一个非负整数表示这 个装备贡献的力量值。接下来的非空字符表示这种装备是基本装备还是高级装备,A表示高级装备,B表示基本装备 。
如果是基本装备,紧接着的两个正整数分别表示它的单价(单位为金币)和数量限制(不超过100)。
如果是高级装备,后面紧跟着一个正整数C,表示这个高级装备需要C种低级装备。后面的2C个数,依次描述某个低级装备的种类和需要的个数。

输出描述

第一行包含一个整数S,表示最多可以提升多少点力量值。

示例1

输入:

10 59
5 A 3 6 1 9 2 10 1
1 B 5 3
1 B 4 3
1 B 2 3
8 A 3 2 1 3 1 7 1
1 B 5 3
5 B 3 3
15 A 3 1 1 5 1 4 1
1 B 3 5
1 B 4 3

输出:

33

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++11(clang++ 3.9) 解法, 执行用时: 808ms, 内存消耗: 45756K, 提交时间: 2019-10-23 20:15:43

#include <cstdio>
#include <cstring>

inline bool isdig(char c)
{
	return c>='0'&&c<='9';
}

inline bool isupp(char c)
{
	return c>='A'&&c<='Z';
}

inline char getch(void)
{
	static char buf[100000],*p1=buf,*p2=buf;

	if(p1!=p2) return *p1++;

	p1=buf;
	p2=p1+fread(buf,1,100000,stdin);

	return p1==p2?EOF:*p1++;
}

template<class T> inline void read(T &num)
{
	bool neg=false;
	char c=getch();

	num=(T)0;
	while(!isdig(c))
	{
		neg|=(c=='-');
		c=getch();
	}
	while(isdig(c))
	{
		num=num*10+c-'0';
		c=getch();
	}
	num=neg?-num:num;

	return;
}

template<typename T> inline T max(T a,T b)
{
	return a>b?a:b;
}

template<typename T> inline T min(T a,T b)
{
	return a<b?a:b;
}

const int N=55,M=2005,L=105,inf=0x3f3f3f3f;
struct EDGE
{
	int nxt,to,val;
	
	EDGE(int n=0,int t=0,int v=0):nxt(n),to(t),val(v){}
}edge[N*N];
int n,m,cnt,wor[N],pri[N],lim[N],head[N],dp[N][L][M],tmp[M],ans[M];
bool vis[N],used[N];

inline void add_edge(int u,int v,int w)
{
	edge[++cnt]=EDGE(head[u],v,w);
	head[u]=cnt;
	
	return;
}

void dfs(int u)
{
	if(vis[u]) return;
	vis[u]=true;
	if(!head[u])
	{
		for(int i=lim[u];i>=0;--i)
			for(register int j=i;j<=lim[u];++j) dp[u][i][j*pri[u]]=wor[u]*(j-i);
		
		return;
    }
	lim[u]=inf;
	for(int i=head[u];i;i=edge[i].nxt)
	{
		int v=edge[i].to,w=edge[i].val;
		
		dfs(v);
		lim[u]=min(lim[u],lim[v]/w);
		pri[u]+=pri[v]*w;
	}
	lim[u]=min(lim[u],m/pri[u]);
	for(int i=lim[u];i>=0;--i)
	{
		memset(tmp,-0x3f,sizeof(tmp));
		tmp[0]=0;
		for(int j=head[u];j;j=edge[j].nxt)
		{
			int v=edge[j].to,w=edge[j].val;
			
			for(int k=m;k>=0;--k)
			{
				int t=-inf;
				
				for(register int l=0;l<=k;++l) t=max(t,tmp[k-l]+dp[v][i*w][l]);
				tmp[k]=t;
			}
		}
		for(int j=0;j<=i;++j)
			for(register int k=0;k<=m;++k) dp[u][j][k]=max(dp[u][j][k],tmp[k]+wor[u]*(i-j));
	}
	
	return;
}
int main()
{
	int c,ki,nd;
	char kd;
	
	read(n);
	read(m);
	for(int i=1;i<=n;++i)
	{
		read(wor[i]);
		kd=getch();
		while(!isupp(kd)) kd=getch();
		if(kd=='A')
		{
			read(c);
			while(c--)
			{
				read(ki);
				read(nd);
				
				add_edge(i,ki,nd);
				used[ki]=true;
			}
		}
		else
		{
			read(pri[i]);
			read(lim[i]);
			
			lim[i]=min(lim[i],m/pri[i]);
		}
	}
	
	memset(dp,-0x3f,sizeof(dp));
	for(int i=1;i<=n;++i)
		if(!used[i])
		{
			dfs(i);
			for(int j=m;j>=0;--j)
				for(register int k=0;k<=j;++k) ans[j]=max(ans[j],ans[j-k]+dp[i][0][k]);
		}
	
	printf("%d",ans[m]);
	return 0;
}

上一题