【JZOJ4245】er【DP】

本文介绍了一款游戏中的装备强化策略,通过使用不同类型的强化符文(赋值、加法、乘法),玩家可以在有限的资源下最大化装备的总效果值。文章详细分析了强化符文的使用顺序和策略,包括如何在两件装备之间分配加法符文,以及如何利用背包问题求解最优解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意:

题目链接:https://jzoj.net/senior/#main/show/4245
小明在业余时间喜欢打电子游戏,不是星际和魔兽这些,是赛尔号一类的游戏。最近小明在玩一款新出的游戏,叫做■■■■■■■■。小明觉得游戏里自己的装备太垃圾了,每次都被大神虐,一怒之下充了■■元准备强化装备。
这个游戏中用于强化装备的道具叫做强化符文。有以下3 种:

  1. 赋值强化符文,对某个装备使用这个符文以后,装备威力值会变为一个常数。因为这个功能很IMBA,可以让一个垃圾装备变得非常牛■,所以它在游戏里很稀有,市场上最多能见到一个。
  2. 加法强化符文,对某个装备使用后,威力值加上一个常数。
  3. 乘法强化符文,对某个装备使用后,威力值乘上一个常数。
    市场上有M 个不同强化符文可以购买,小明有N 件装备准备强化,他只能购买K 个强化符文,然后以任意顺序使用这些符文,强化他的任意装备(一个装备可以不强化也可以强化多次)。根据游戏的设定,所有装备威力值乘积为总效果。请为他设计一个购买和强化方案,使强化后的所有装备总效果值最大。
    由于小明RP 不太好,打BOSS 都不掉神装,所以他的装备不超过两件。

思路:

首先,加法符文肯定是在乘法符文之前用的。设原效果为 a a a,加法符文为 x x x,乘法符文为 y y y,若先用加法符文,那么得到 y ( a + x ) = a y + x y y(a+x)=ay+xy y(a+x)=ay+xy,若先用乘法符文,则有 a y + x ay+x ay+x,在没有负数的情况下,明显前者更优。
其次,赋值符文肯定最先使用。若不是最先使用,那么前面的加法乘法就相当于没有用了,又被重新赋值。

接下来的叙述全部省略的赋值符文,因为赋值符文只会有1个,分情况讨论一下就行。

先考虑 n = 1 n=1 n=1的情况。很明显, n = 1 n=1 n=1的情况中,若使用 x x x个加法符文,则使用 k − x k-x kx个乘法符文。肯定选择尽量大的会更优,于是就排个序,然后记录前缀和以及前缀积即可。
再来看 n = 2 n=2 n=2的情况。因为最终答案是两个装备相乘。所以乘法符文放哪边答案都是一样的,所以着重考虑加法符文的放置。
明显的,加法符文就是一个背包问题,直接按照背包问题来求,对于每一个符文选择或不选择即可。


代码:

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;

const int N=110;
int n,m,k,s1,s2,x,y,give;
int a[N],mul[N],add[N],sum1[N],f[N][2010*N],maxn[N];
double sum2[N],ans;

bool cmp(int x,int y)
{
	return x>y;
}

int main()
{
	scanf("%d%d%d",&n,&m,&k);
	for (int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	for (int i=1;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		if (x==1) give=y;
		if (x==2) add[++s1]=y;
		if (x==3) mul[++s2]=y;
	}
	sort(add+1,add+1+s1,cmp);
	sort(mul+1,mul+1+s2,cmp);
	sum1[0]=a[1]+a[2];
	for (int i=1;i<=k;i++)
		sum1[i]=sum1[i-1]+add[i];
	for (int i=1;i<=k;i++)
		sum2[i]=sum2[i-1]+log(mul[i]);
	if (n==1)
	{
		if (give)
			for (int i=0;i<k;i++)
				ans=max(ans,log(give+sum1[min(s1,i)])+sum2[min(s2,k-i-1)]);
		for (int i=0;i<=k;i++)
			ans=max(ans,log(sum1[min(s1,i)])+sum2[min(s2,k-i)]);
	}
	else
	{
		memset(f,0xcf,sizeof(f));
		f[0][a[1]]=a[1]*a[2];
		for (int i=0;i<=s1;i++)
			for (int j=a[1];j<=sum1[i];j++)
			{
				f[i+1][j]=max(f[i+1][j],f[i][j]+add[i+1]*j);
				f[i+1][j+add[i+1]]=max(f[i+1][j+add[i+1]],f[i][j]+add[i+1]*(sum1[i]-j));
				maxn[i]=max(maxn[i],f[i][j]);
			}
		for (int i=0;i<=k;i++)
			ans=max(ans,log(maxn[min(i,s1)])+sum2[min(k-i,s2)]);
		if (give)
		{
			k--;
			f[0][give]=give*a[1];
			sum1[0]=give+a[1];
			for(int i=1;i<=k;i++)
	  			sum1[i]=sum1[i-1]+add[i];
			for(int i=0;i<=k;i++)
			{
				for(int j=give;j<=sum1[i];j++)
				{
					f[i+1][j]=max(f[i][j]+add[i+1]*j,f[i+1][j]);
					f[i+1][j+add[i+1]]=max(f[i][j]+add[i+1]*(sum1[i]-j),f[i+1][j+add[i+1]]);
					maxn[i]=max(maxn[i],f[i][j]);
				}
			}
			for(int i=0;i<=k;i++)
				ans=max(ans,log(maxn[min(i,s1)])+sum2[min(k-i,s2)]);
				
			//////////////////////////////////////////////////////////////////////////////////////////////////////////
			
			memset(maxn,0,sizeof(maxn));
			memset(f,0,sizeof(f));
			f[0][give]=give*a[2];
			sum1[0]=give+a[2];
			for(int i=1;i<=k;i++)
	  			sum1[i]=sum1[i-1]+add[i];
			for(int i=0;i<=k;i++)
			{
				for(int j=give;j<=sum1[i];j++)
				{
					f[i+1][j]=max(f[i][j]+add[i+1]*j,f[i+1][j]);
					f[i+1][j+add[i+1]]=max(f[i][j]+add[i+1]*(sum1[i]-j),f[i+1][j+add[i+1]]);
					maxn[i]=max(maxn[i],f[i][j]);
				}
			}
			for(int i=0;i<=k;i++)
				ans=max(ans,log(maxn[min(i,s2)])+sum2[min(k-i,s1)]);
		}
	}
	printf("%0.3f\n",ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值