CF1167F Solution

题目链接

题解

⭐:(inf)若需多次加减不宜过大,容易溢出。

dp题呐~

状态:(dp[i][j])表示前(i)轮距离上次(包括当前卡牌)触发双倍已经经过(j)张卡时的最大伤害。

初始值:(dp[i][j]=inf,dp[i][0]=0quad (0le ile n,1le jle 9))

转移方程:设(x1,x2,x3)分别为(c=1)卡牌的最大、次大、第三大(d)值,(y,z)分别为(c=2,3)卡牌的最大(d)值。

[dp[i][j]=dp[i-1][j]\ dp[i][(j+3)\%10]=max(dp[i][(j+3)\%10],dp[i-1][j]+x1*2+x2+x3)quad (jge 7)\ dp[i][j+3]=max(dp[i][j+3],dp[i-1][j]+x1+x2+x3)quad (j<7)\ dp[i][(j+2)\%10]=max(dp[i][(j+2)\%10],dp[i-1][j]+max(x1*2+x2,x1*2+y,y*2+x1))quad (jge 8)\ dp[i][j+2]=max(dp[i][j+2],dp[i-1][j]+max(x1+x2,y+x1))quad (j<8)\ dp[i][0]=max(dp[i][0],dp[i-1][j]+max(x1,max(y,z))*2)quad (j=9)\ dp[i][j+1]=max(dp[i][j+1],dp[i-1][j]+max(x1,y,z))quad (j<9)\ (1le ile n,9ge jge 0) ]

好长,但基本思路就是1行为不选的转移方程,2,4,6行为触发双倍时的方程,其余为普通转移。注意(j)需倒序枚举,否则会从当前回合的状态转移而来。

目标状态:(max_{i=0}^{ile 9} dp[n][i])

AC代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+10,inf=0x7fffffff;
struct node {int c,d;} a[N];
int dp[N][15];
signed main()
{
	int n,k,ans=0;
	scanf("%lld",&n);
    //初始化
	for(int i=0;i<=n;i++)
		for(int j=0;j<=9;j++) dp[i][j]=-inf;
	for(int i=0;i<=n;i++) dp[i][0]=0;
    //dp
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&k);
		for(int j=1;j<=k;j++) scanf("%lld%lld",&a[j].c,&a[j].d);
        //贪心求出x1,x2,x3,y,z
		int x1=-inf,x2=-inf,x3=-inf,y=-inf,z=-inf;
		for(int j=1;j<=k;j++)
		{
			if(a[j].c==1)
			{
				if(a[j].d>x1) x3=x2,x2=x1,x1=a[j].d;
				else if(a[j].d>x2) x3=x2,x2=a[j].d;
				else if(a[j].d>x3) x3=a[j].d;
			}
			else if(a[j].c==2) y=max(y,a[j].d);
			else z=max(z,a[j].d);
		}
        //转移
		for(int j=9;j>=0;j--) dp[i][j]=dp[i-1][j];
		for(int j=9;j>=0;j--)
		{
			if(j>=7) dp[i][(j+3)%10]=max(dp[i][(j+3)%10],dp[i-1][j]+x1*2+x2+x3);
			else dp[i][j+3]=max(dp[i][j+3],dp[i-1][j]+x1+x2+x3);
			if(j>=8) dp[i][(j+2)%10]=max(dp[i][(j+2)%10],dp[i-1][j]+max(x1*2+x2,max(x1*2+y,y*2+x1)));
			else dp[i][j+2]=max(dp[i][j+2],dp[i-1][j]+max(x1+x2,y+x1));
			if(j==9) dp[i][0]=max(dp[i][0],dp[i-1][j]+max(x1,max(y,z))*2);
			else dp[i][j+1]=max(dp[i][j+1],dp[i-1][j]+max(x1,max(y,z)));
		}
	}
    //统计答案
	for(int i=0;i<=9;i++) ans=max(ans,dp[n][i]);
	printf("%lld",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/violetholmes/p/14607442.html