【动态规划】【倒序】codeforces102056I Misunderstood … Missing

本文介绍了一种倒序动态规划策略,用于解决游戏中的最大化伤害输出问题。通过记录攻击力和增量变化,文章详细解释了如何逆向思考,避免了传统顺向DP中状态空间的爆炸性增长。关键在于理解倒序DP如何简化复杂度,通过精妙的状态转移方程,实现了高效求解。

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

I. Misunderstood … Missing
time limit per test1.0 s
memory limit per test256 MB
inputstandard input
outputstandard output
Warm sunshine, cool wind and a fine day, while the girl watching is pursuing in chaos. Rikka reached out her hand and got the garland on her head, finding LCR with the immortal smile. The dream ended up waking, but the doubts will never disappear. In the end, without knowing about LCR, Rikka was invited to Shuyuan Men, a street of Chinese traditional arts in Xi’an.

“Is it enough to use the stored wires?”

“No problem… Those leaders are only concerned about expanding EC Final for the school’s and their ‘achievements’. All chores are ours. It is fine to simply connect those wiring boards in the series for each row.”

Their conversation engaged Rikka. Feeling strange, she decided to follow them. But before all, she needs to beat the devil in her heart.

Rikka has an aggressivity A and an increment D of it, which are both 0 initially. There are n rounds in total. For i=1,2,…,n, at the beginning of i-th round Rikka’s aggressivity A increases by the increment D, and then she can do one of the following:

Attack and cause a damage of (A+ai).
Use the Omnipotent Garland from LCR to increase the increment D by bi.
Use her Schwarz Sechs Prototype Mark II to increase the aggressivity A by ci.
Rikka wonders the maximal possible damage she could cause in total. Could you help her?

Input
The first line contains a single integer T (1≤T≤10), the number of test cases. Then T test cases follow.

The input format of each test case is as follows:

The first line contains a single integer n (1≤n≤100), the number of rounds.

The following n lines contain {ai},{bi},{ci} for i=1,2,…,n. The i-th line among them contains three integers ai,bi,ci (1≤ai,bi,ci≤109) separated by spaces in order.

It is guaranteed that the sum of n in all test cases is at most 100.

Output
Output T lines; each line contains one integer, the answer to that test case.


 今天和队友们一起模拟了EC-final的比赛。其间Hardict解了一道我根本没思路的dp题,后来仔细领会了一下,感觉确实很精彩,于是记录一下(感谢这么可靠的队友!)
 首先题目肯定是dp了。一般人的思路肯定是顺着来做,包括我。可以发现顺着做的话,无论如何都要记录当前的攻击力A和当前的增量D,这两个数字本身就是大,不可能作为dp状态的维度。队友提醒我倒着做的时候还没反应过来QwQ。
 倒着dp有什么好处呢?我们知道,我们之所以顺着来的时候要记录A和D,是因为不记录必然有后效性。但有后效性不意味着有“前效性”,首先可以发现,倒着每做一次选择,它对答案产生的贡献更好确定。具体怎么确定呢,我们知道,只要记录考虑到第i步时,此后攻击了j步,那么第三个选择的贡献可以确定,是c[i]*j,而第二个选择,还需要记录这些攻击的下标之和(这个设计也很精彩!)
 具体的转移方程看代码,另外附他人详细的题解:https://www.cnblogs.com/Cwolf9/p/10138441.html
 状态太多的话可以考虑滚动数组。

#include<cstdio>
#include<algorithm>
using namespace std;
using LL=long long;

LL dp[2][105][5505],a[105],b[105],c[105],ans,tmp,o;
int T,n;

inline bool check(int i, int j, int k)
{
	return i<=n&&j>0&&(i*2+j-1)*j/2<=k&&(n*2-j+1)*j/2>=k;  //检查状态合法性
}

int main()
{
	scanf("%d",&T);
	while(T--)
	{
		ans=0;
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
			scanf("%lld%lld%lld",&a[i],&b[i],&c[i]);
		for(int i=n;i>0;i--)
		{
			for(int j=1;j<=n-i+1;j++)
				for(int k=(i*2+j-1)*j/2;k<=(n*2-j+1)*j/2;k++)
				{
					tmp=check(i+1,j,k)?dp[o^1][j][k]+max(c[i]*j,(k-i*j)*b[i]):0;
					dp[o][j][k]=max((check(i+1,j-1,k-i)?dp[o^1][j-1][k-i]:0)+a[i],tmp);
				}
			o^=1;
		}
		for(int j=1;j<=n;j++)
			for(int k=(j+1)*j/2;k<=(n*2-j+1)*j/2;k++)
				ans=max(dp[o^1][j][k],ans);
		printf("%lld\n",ans);
	}
	return 0;
}
### 关于Codeforces平台上的动态规划问题 在Codeforces这样的编程竞赛平台上,动态规划(Dynamic Programming, DP)是一类非常重要的算法技术。这类题目通常涉及优化子结构和重叠子问题两个特性。 #### 动态规划示例解析 考虑一个典型的DP问题,在给定条件下求解最优方案的数量或具体路径等问题。例如,在某些情况下,可能需要计算达到特定状态所需的最少步数或是最大收益等[^1]。 对于具体的例子而言,假设有一个序列`a[]`,目标是从左到右遍历此序列并决定是否选取当前元素加入集合中,最终目的是让所选元素之和尽可能大而不超过某个上限值M。这个问题可以通过定义二维数组dp[i][j]表示从前i个物品里挑选若干件放入容量为j的背包可以获得的最大价值来建模: - 如果不取第i项,则`dp[i][j]=dp[i−1][j]`; - 若选择第i项且其重量w不超过剩余空间j,则更新为`max(dp[i−1][j], dp[i−1][j-w]+v)`其中v代表该项的价值; 最后的结果保存在`dp[n][m]`处(n为总项目数量,m为目标体积)[^2]。 ```cpp #include <iostream> using namespace std; const int N = 1e3 + 5; int w[N]; // weights of items int v[N]; // values of items long long f[N][N]; void knapsack(int n, int m){ for (int i = 1; i <= n; ++i) { for (int j = 0; j <= m; ++j) { f[i][j] = f[i - 1][j]; if(j >= w[i]) f[i][j] = max(f[i][j],f[i - 1][j - w[i]] + v[i]); } } } ``` 上述代码展示了如何利用记忆化搜索的方式实现简单的0/1背包问题解决方案,这同样适用于其他形式更复杂的动态规划挑战。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值