AT4120 [ARC096D] Sweet Alchemy

题目传送门

分析:
看到这个限制条件构成了一个树形结构,相当于儿子节点的生产数一定不小于父亲节点,且不比父亲节点多超过\(D\)
差分一下,如果一个节点要制造物品,那么其子树内的节点全部都制造一个物品,非根节点最多造\(D\)个物品
效果相同,并且将每个节点的代价和收益变为子树和,我们就可以脱离树形结构直接多重背包了
但是\(D\leq 10^9\)不能够枚举
我们回到最开始学动规背包时,相想必大家在解决背包问题时一定想过一个贪心:
一个物品重量为\(w\),价值为\(v\),我们把物品按\(\frac{v}{w}\)从大到小排序,贪心加入
这样做会在当背包剩余空间不够大的时候出现问题,相信大家也把自己驳倒过
但是在背包空间足够大时,这样的做法就没有问题
我们可以在背包空间不够大的时候做多重背包,剩余的体积用于贪心加入物品
假设有两个物品\(i,j\)满足\(\frac{v_i}{w_i}>\frac{v_j}{w_j}\),那么在收益相等(选了\(v_j\)\(i\),选了\(v_i\)\(j\))的情况下,选\(v_j\)\(i\)显然会更优
从而在比\(\frac{v_i}{w_i}\)大的物品还能加的时候,比\(\frac{v_i}{w_i}\)小的至多会选\(v_i-1\)
我们这道题一个点的\(v\)为子树和,最大为\(n\)
相当于做背包的每种物品最多有\(min(n,D)\)个,背包体积最大为\(n^3\)
使用二进制分组优化一下,复杂度可以接受
剩下的暴力加入就好了
总复杂度\(O(n^4logX)\)

#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
#include<queue>
#include<bitset>
#include<map>
#include<set>

#define maxn 55
#define maxm 125005
#define INF 0x3f3f3f3f
#define MOD 1000000007

using namespace std;

inline int getint()
{
	int num=0,flag=1;char c;
	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
	while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
	return num*flag;
}

int n,X,d;
int fa[maxn];
struct node{
	long long v;
	int w,id;
}a[maxn];
inline bool cmp(node a,node b){return a.w*b.v>b.w*a.v;}
long long dp[maxm];

int main()
{
	n=getint(),X=getint(),d=getint();
	a[1].v=getint();
	for(int i=2;i<=n;i++)a[i].v=getint(),fa[i]=getint();
	for(int i=1;i<=n;i++)a[i].id=i,a[i].w=1;
	for(int i=n;i>1;i--)a[fa[i]].v+=a[i].v,a[fa[i]].w+=a[i].w;
	int L=min(n,d);
	memset(dp,INF,sizeof dp),dp[0]=0;
	for(int i=1;i<=n;i++)
	{
		int x=L;
		for(int j=0;(1<<j)<=x;j++)
		{
			int w=a[i].w<<j;
			long long v=a[i].v<<j;
			for(int k=maxm-1;k>=w;k--)dp[k]=min(dp[k],dp[k-w]+v);
			x-=1<<j;
		}
		if(x)
		{
			int w=a[i].w*x;
			long long v=a[i].v*x;
			for(int j=maxm-1;j>=w;j--)dp[j]=min(dp[j],dp[j-w]+v);
		}
	}
	sort(a+1,a+n+1,cmp);
	while(a[n].id!=1)n--;
	long long ans=0;
	for(int i=0;i<maxm;i++)
	{
		if(dp[i]>X)continue;
		long long w=i,v=dp[i];
		for(int j=1;j<n;j++)
		{
			long long c=min(1ll*d-L,(X-v)/a[j].v);
			w+=c*a[j].w,v+=c*a[j].v;
		}
		long long c=(X-v)/a[n].v;
		w+=c*a[n].w,v+=c*a[n].v;
		ans=max(ans,w);
	}
	printf("%lld\n",ans);
}

posted @ 2020-07-08 15:50  Izayoi_Doyo  阅读(127)  评论(0编辑  收藏  举报