Growth (dp)

题目链接
题目描述:
弱弱有两个属性a和b,这两个属性初始的时候均为0,每一天他可以通过努力,让a涨1点或b涨1点。
为了激励弱弱努力学习,我们共有n种奖励,第i种奖励有xi,yi,zi三种属性,若a ≥ xi且b ≥ yi,则弱弱在接下来的每一天都可以得到zi的分数。
问m天以后弱弱最多能得到多少分数。
样例输入

2 4
2 1 10
1 2 20

样例输出

50

dp[i][j]表示a值达到xi, b值达到yi,可以获得的奖励的最大值。
很显然
dp[i + 1][j] = max(dp[i + 1][j], dp[i][j] + (x[i + 1] - x[i] - 1) * v[i][j] + v[i + 1][j]);
dp[i][j + 1] = max(dp[i][j + 1], dp[i][j] + (y[j + 1] - y[j] - 1) * v[i][j] + v[i][j + 1]);
其中, v[i][j]是说a达到了x[i], b达到了y[i],接下来每天可以获得的奖励。
v[i][j] = v[i - 1][j] + v[i][j - 1] - v[i - 1][j - 1] + t[i][j];
其中t[i][j]为满足x=i,y=j的奖励的总和。

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn = 1e3 + 100;

map<pair<int, int>, int> p;
set<int> sx, sy;
int x[maxn], y[maxn];
ll dp[maxn][maxn], v[maxn][maxn];

int main()
{
   int n, m;
   int cnt1 = 1, cnt2 = 1;
   scanf("%d %d", &n, &m);
   for(int i = 0; i < n; i++) {
       int tx, ty, tz;
       scanf("%d %d %d", &tx, &ty, &tz);
       p[pair<int, int>(tx, ty)] += tz;
       if(!sx.count(tx)) sx.insert(tx), x[cnt1++] = tx;
       if(!sy.count(ty)) sy.insert(ty), y[cnt2++] = ty;
   }

   sort(x + 1, x + cnt1);
   sort(y + 1, y + cnt2);

   for(int i = 1; i < cnt1; i++) {
     for(int j = 1; j < cnt2; j++) {
        if(!p[pair<int, int>(x[i], y[j])]) v[i][j] = v[i - 1][j] + v[i][j - 1] - v[i - 1][j - 1];
        else v[i][j] = v[i - 1][j] + v[i][j - 1] - v[i - 1][j - 1] + p[pair<int, int>(x[i], y[j])];
     }
   }

   for(int i = 0; i < cnt1; i++) {
      for(int j = 0; j < cnt2; j++) {
        dp[i + 1][j] = max(dp[i + 1][j], dp[i][j] + (x[i + 1] - x[i] - 1) * v[i][j] + v[i + 1][j]);
        dp[i][j + 1] = max(dp[i][j + 1], dp[i][j] + (y[j + 1] - y[j] - 1) * v[i][j] + v[i][j + 1]);
      }
   }

   ll ans = 0;
   for(int i = 1; i < cnt1; i++) {
    for(int j = 1; j < cnt2; j++) {
        ll t = dp[i][j] + (m - x[i] - y[j]) * v[i][j];
        ans = max(ans, t);
    }
   }
   printf("%lld\n", ans);
}

猜你喜欢

转载自blog.csdn.net/deerly_/article/details/81584521