CF1167F Solution

题目链接

题解

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

dp题呐~

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

初始值:\(dp[i][j]=inf,dp[i][0]=0\quad (0\le i\le n,1\le j\le 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 (j\ge 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 (j\ge 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)\\ (1\le i\le n,9\ge j\ge 0) \]

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

目标状态:\(max_{i=0}^{i\le 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;
}
posted @ 2021-04-01 17:46  violet_holmes  阅读(45)  评论(0编辑  收藏  举报