2019牛客暑期多校训练营(第六场)J-Upgrading Technology

题目链接:https://ac.nowcoder.com/acm/contest/886/J
题意:题目中的货币当做技能点,题目中给n个技能,每个技能满级都是m级,技能升级可能是获得技能点,也可能是消耗技能点,当n个技能的最小等级技能分别为1到m级是,分别会获得d1 d2 …dn 技能点,d【i】可以是正的,也可以是负的。求最多能盈利多少技能点
题解:求出n个技能中最小等级分别是0级,1级,2级,…,m级的最大盈利,然后找出最大的那个就是答案。先求出技能全部升到0级,1级,2级,… ,m级的盈利,然后对于每种情况,每个技能求出继续往后升级的最大盈利,是正的就加上,但不能全加,全加最小技能等级就不是当前这种情况了,更新完后的就是最小等级分别是0级,1级,2级,…,m级的最大盈利。怎么求继续往后升级的最大盈利,用dp,假如只有一行,技能升级所需的技能点为v数组,dp[m]=0,因为不能继续往后升了,然后从后往前,dp[i]=max( v[i+1],v[i+1] + dp[i+1] )。

#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn = 1005;
struct node {
	ll value[maxn];
	ll dp[maxn];
}p[maxn];
ll he[maxn];
ll ans;
ll de[maxn];
int n, m;
int main()
{
	int lun=0;
	int t;
	cin >> t;
	while (t--) {
		lun++;
		scanf("%d%d", &n, &m);
		memset(he, 0, sizeof(he));
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= m; j++) {
				scanf("%lld", &p[i].value[j]);
				p[i].value[j] *= -1;
				he[j] += p[i].value[j];
			}
			p[i].dp[m] = 0;
			for (int j = m - 1; j >= 0; j--) {
				p[i].dp[j] = max(p[i].value[j + 1], p[i].value[j + 1] + p[i].dp[j + 1]);
			}
		}
		for (int i = 1; i <= m; i++) {
			scanf("%lld", &de[i]);
			he[i] += de[i];
			he[i] += he[i - 1];
		}
		ans = 0;
		for (int i = 0; i < m; i++) {
			bool full = true;
			for (int j = 1; j <= n; j++) {
				if (p[j].dp[i] > 0) {
					he[i] += p[j].dp[i];
				}
				if (p[j].dp[i] < 0)
					full = false;
			}
			if (full == true) {
				ll min0 = p[1].dp[i];
				for (int j = 2; j <= n; j++) {
					min0 = min(p[j].dp[i], min0);
				}
				he[i] -= min0;
			}
		}


		for (int i = 0; i <= m; i++) {
			ans = max(ans, he[i]);
		}
		printf("Case #%d: %lld\n",lun, ans);
	}
}

你可能感兴趣的:(dp)