CF GYM 1020561 I. Misunderstood … Missing解题报告(逆序动态规划)

回眸只為那壹抹淺笑 提交于 2019-11-27 12:08:38

题目链接:http://codeforces.com/gym/102056/problem/I
题目描述:
I. Misunderstood … Missing

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.

Example
input
3
2
3 1 2
3 1 2
3
3 1 2
3 1 2
3 1 2
5
3 1 2
3 1 2
3 1 2
3 1 2
3 1 2
output
6
10
24

题目大意:
你初始有D,A都为0, 游戏有n轮, 每轮有三个选项你可以选择其一:分别为对敌人造成A+ai的伤害, 使自己的A增加ci, 使自己的D增加bi, 每回合开始时你的A会增加D, 保证ai, bi, ci为正整数。

题解:
因为有三个选项对应了三种决择, 而考虑到贪心的不正确性, 我们可以考虑dp, 首先对于最后一回合时我们肯定选择攻击不会选择使A或者D增加, 但是dp又有一个问题:如果我们正着dp当我们选择D或者A增加时会对后面回合造成影响, 不满足dp的无后效性, 因为我们想到了最后一次必定攻击,我们考虑一下能不能倒着dp。

首先考虑如果空间够用, 我们尝试把攻击的位置进行状态压缩, dp[i][j]表示到i是j对应的攻击状态能打的最大伤害, 显然如果本轮攻击, 那么就对应dp[i+1][k] + a[i](k为不包含当轮攻击的状态)如果选择A增加,那么之前处理过的伤害会增加而dp[i][j] = dp[i+1][j] + k * ai (k为j对应的攻击次数)然后如果我们这轮让D增加, 那么我们会在对应攻击的地方伤害会有增加我们设攻击的位置为p1,p2…pk那么考虑伤害的增量:(i - p1) * bi, (i - p2) * bi …(i - pk) * bi我们把他们加起来后发现增量为:i * k * bi - (p1+p2+…+pk) * bi其中k为攻击次数, 那么我们发现选择D增加,伤害的增量只与k(攻击次数),bi,(p1+p2+…+pk)有关所以我们可以这样定义状态dp[i][j][k]表示到i对应攻击次数j攻击位置的和k(p1+p2+…+pk)对应的最大值所以转移就变成了:dp[i][j][k]= dp[i+1][j-i][k] + ai(攻击)dp[i][j][k] = dp[i+1][j][k] + ci * j(选择增加A)dp[i][j][k] = dp[i+1][j][k] + i * j * bi - k * bi(选择增加D)
最后考虑空间问题由于至于i与i+1有关所以滚动数组滚一滚。
代码:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

const int maxn = 110;

typedef long long ll;

using namespace std;

int n, t;
ll ans;
ll a[maxn], b[maxn], c[maxn], dp[2][maxn][(1+maxn)*maxn/2];

ll read(){
	ll x = 0, f = 1;
	char ch;
	do{
		ch = getchar();
		if (ch == '-') f = -1;
	}while(ch < '0' || ch > '9');
	do{
		x = x * 10 + ch - 48;
		ch = getchar();
	}while(ch >= '0' && ch <= '9');
	return x * f;
}
int main(){
	t = read();
	while(t --){
		n = read();
		for (int i = 1;i <= n;i ++) a[i] = read(), b[i] = read(), c[i]= read();
		int pos = 1, laspos = 0;
		memset(dp, -1, sizeof(dp));
		dp[0][1][n] = a[n];
		ans = a[n];
		for (int i = n-1;i >= 1;i --){
			memset(dp[pos], -1, sizeof(dp[pos]));
			for (int j = 1;j <= n-i+1;j ++){
				for (int k = n;k <= (n + i) * (n - i + 1) / 2;k ++){
					if (dp[laspos][j-1][k-i] != -1) dp[pos][j][k] = max(dp[pos][j][k], dp[laspos][j-1][k-i] + a[i]);
					if (dp[laspos][j][k] != -1) 
						dp[pos][j][k] = max(dp[pos][j][k], dp[laspos][j][k] + (k - j * i) * b[i]),
						dp[pos][j][k] = max(dp[pos][j][k], dp[laspos][j][k] + j * c[i]);
					ans = max(dp[pos][j][k], ans);
				}
			}
			laspos = pos;
			pos ^= 1;
		}
		cout << ans << endl;
	}
	return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!