2023“钉耙编程”中国大学生算法设计超级联赛(1)Mr. Liang play Card Game

2023“钉耙编程”中国大学生算法设计超级联赛(1)Mr. Liang play Card Game

题目大意

有一款卡牌游戏,游戏规则如下:有 n n n张卡片从左到右排列在一行上。每张卡片都有一个种类和一个等级(初始时,所有卡片的等级都是 1 1 1)。你可以执行以下操作任意次:

  • 选择一张卡片并打出。每种卡片类型都有一个值 v i v_i vi,打出一张等级为 k k k的卡片可以获得 P k × v i P^k\times v_i Pk×vi的收益。但卡片等级有一个限制,最大等级为 R R R
  • 选择两张相邻且类型和等级都相同的卡片,将它们合并成一张更高等级的卡片

给出卡牌数量 n n n,卡牌种类 m m m n n n张卡片的排列顺序, v i v_i vi P P P R R R,求最终能获得的最大收益是多少。

t t t组数据。

1 ≤ t ≤ 50 , 1 ≤ n ≤ 100 , 1 ≤ m ≤ 20 , 1 ≤ R ≤ 20 , 1 ≤ P ≤ 10 1\leq t\leq 50,1\leq n\leq 100,1\leq m\leq 20,1\leq R\leq 20,1\leq P\leq 10 1t50,1n100,1m20,1R20,1P10

数据保证 n n n值超过 20 20 20的数据组数不超过 10 10 10


题解

f l , r , x , k f_{l,r,x,k} fl,r,x,k表示用区间 [ l , r ] [l,r] [l,r]中的卡牌操作后只剩下一张等级为 x x x,种类为 k k k的卡牌所能获得的最大收益, f l , r , 0 , 0 f_{l,r,0,0} fl,r,0,0表示用区间 [ l , r ] [l,r] [l,r]中的卡牌经过操作全部打出所能得到的最大收益。

我们考虑如何转移。

先考虑区间中只剩一张卡牌时的最大收益。如果这张卡牌的等级为 1 1 1,则我们可以枚举卡牌的位置 i i i,求出将 [ l , i − 1 ] [l,i-1] [l,i1] [ i + 1 , r ] [i+1,r] [i+1,r]上的所有卡牌打出之后的所能获得的最大收益。

f l , r , 1 , k = max ⁡ i = l r { f l , i − 1 , 0 , 0 + f i + 1 , r , 0 , 0 } f_{l,r,1,k}=\max\limits_{i=l}^r\{f_{l,i-1,0,0}+f_{i+1,r,0,0}\} fl,r,1,k=i=lmaxr{fl,i1,0,0+fi+1,r,0,0}

注意要当 k = a i k=a_i k=ai时才能取 m a x max max

当等级大于 1 1 1时,我们可以枚举左右区间的断点 i i i,从 [ l , i ] [l,i] [l,i] [ i + 1 , r ] [i+1,r] [i+1,r]分别等到种类相同但等级低一级的卡牌,合并得到答案。

f l , r , x , k = max ⁡ i = l r − 1 { f l , i , x − 1 , k + f i + 1 , r , x − 1 , k } f_{l,r,x,k}=\max\limits_{i=l}^{r-1}\{f_{l,i,x-1,k}+f_{i+1,r,x-1,k}\} fl,r,x,k=i=lmaxr1{fl,i,x1,k+fi+1,r,x1,k}

其中 x > 1 x>1 x>1

再考虑如何计算 f l , r , 0 , 0 f_{l,r,0,0} fl,r,0,0。先枚举区间 [ l , r ] [l,r] [l,r]可以由哪两个合并得到,这类答案用 w 1 w1 w1来储存。

w 1 = max ⁡ i = l r − 1 { f l , i , 0 , 0 + f i + 1 , r , 0 , 0 } w1=\max\limits_{i=l}^{r-1}\{f_{l,i,0,0}+f_{i+1,r,0,0}\} w1=i=lmaxr1{fl,i,0,0+fi+1,r,0,0}

再枚举区间 [ l , r ] [l,r] [l,r]可以剩下什么样的卡牌,将其打出后求出能得到收益,再取最大值,这类答案用 w 2 w2 w2来储存。

w 2 = max ⁡ x = 1 R max ⁡ k = 1 m { f l , r , x , k + P x ⋅ v k } w2=\max\limits_{x=1}^R\max\limits_{k=1}^m\{f_{l,r,x,k}+P^x\cdot v_k\} w2=x=1maxRk=1maxm{fl,r,x,k+Pxvk}

由此即可得到 f l , r , 0 , 0 f_{l,r,0,0} fl,r,0,0

f l , r , 0 , 0 = max ⁡ { w 1 , w 2 } f_{l,r,0,0}=\max\{w1,w2\} fl,r,0,0=max{w1,w2}

最后的答案为 f 1 , n , 0 , 0 f_{1,n,0,0} f1,n,0,0

时间复杂度为 O ( n 3 m R ) O(n^3mR) O(n3mR)。在 1 ≤ n ≤ 100 1\leq n\leq 100 1n100的情况下,等级的最大值不超过 7 7 7,而且 n n n较大的数据组数较少,所以这是可行的。

code

#include<bits/stdc++.h>
using namespace std;
int t,n,m,R;
long long P,a[105],v[105],mi[25],f[105][105][25][25];
int main()
{
	scanf("%d",&t);
	while(t--){
		scanf("%d%d%d%lld",&n,&m,&R,&P);
		mi[0]=1;
		for(int i=1;i<=10;i++) mi[i]=mi[i-1]*P;
		for(int i=1;i<=n;i++){
			scanf("%lld",&a[i]);
		}
		for(int i=1;i<=m;i++){
			scanf("%lld",&v[i]);
		}
		for(int l=1;l<=n;l++)
		for(int r=l;r<=n;r++){
			for(int i=0;i<=R;i++)
			for(int j=0;j<=m;j++) f[l][r][i][j]=-1e18;
			f[l][r][0][0]=0;
		}
		for(int i=1;i<=n;i++){
			f[i][i][1][a[i]]=0;
			f[i][i][0][0]=v[a[i]];
		}
		for(int len=2;len<=n;len++){
			for(int l=1,r=len;r<=n;l++,r++){
				for(int w=l;w<=r;w++){
					f[l][r][1][a[w]]=max(f[l][r][1][a[w]],f[l][w-1][0][0]+f[w+1][r][0][0]);
				}
				for(int i=2;i<=R;i++){
					for(int j=1;j<=m;j++){
						for(int w=l;w<=r-1;w++){
							f[l][r][i][j]=max(f[l][r][i][j],f[l][w][i-1][j]+f[w+1][r][i-1][j]);
						}
					}
				}
				long long v1=-1e18,v2=-1e18;
				for(int i=l;i<=r-1;i++){
					v1=max(v1,f[l][i][0][0]+f[i+1][r][0][0]);
				}
				for(int i=1;i<=R;i++){
					for(int j=1;j<=m;j++){
						v2=max(v2,f[l][r][i][j]+mi[i-1]*v[j]);
					}
				}
				f[l][r][0][0]=max(v1,v2);
			}
		}
		printf("%lld\n",f[1][n][0][0]);
	}
	return 0;
}
  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值