弱弱有两个属性 a a a 和 b b b,这两个属性初始的时候均为 0 0 0,每一天他可以通过努力,让 a a a 涨 1 1 1 点或 b b b 涨 1 1 1点。
为了激励弱弱努力学习,我们共有 n n n 种奖励,第 i i i 种奖励有 x i , y i , z i x_i,y_i,z_i xi,yi,zi 三种属性,若 a ≥ x i a≥ x_i a≥xi 且 b ≥ y i b≥ y_i b≥yi,则弱弱在接下来的每一天都可以得到 z i z_i zi 的分数。
问 m m m 天以后弱弱最多能得到多少分数。
第一行一个两个整数 n n n 和 m m m ( 1 ≤ n ≤ 1000 , 1 ≤ m ≤ 2000000000 ) (1≤ n≤ 1000,1≤ m≤ 2000000000) (1≤n≤1000,1≤m≤2000000000)。
接下来 n n n 行,每行三个整数 x i , y i , z i x_i,y_i,z_i xi,yi,zi ( 1 ≤ x i , y i ≤ 1000000000 , 1 ≤ z i ≤ 1000000 ) (1≤ x_i,y_i≤ 1000000000,1≤ z_i ≤ 1000000) (1≤xi,yi≤1000000000,1≤zi≤1000000)。
一行一个整数表示答案。
输入
2 4
2 1 10
1 2 20
输出
50
在样例中,弱弱可以这样规划:第一天 a a a 涨 1 1 1,第二天 b b b 涨 1 1 1,第三天 b b b 涨 1 1 1,第四天 a a a 涨 1 1 1。
共获得 0 + 0 + 20 + 30 = 50 0+0+20+30=50 0+0+20+30=50 分。
定义 v [ i ] [ j ] v[i][j] v[i][j],为保持 a = i , b = j a=i,b=j a=i,b=j 的状态,在将来 m − i − j m-i-j m−i−j 天,每天能获得的分数。定义 d p [ i ] [ j ] dp[i][j] dp[i][j] 表示,当恰好达到 a = i , b = j a=i,b=j a=i,b=j 的状态时,能够获得的最高分。
初始状态为 v [ x i ] [ y i ] = z i v[x_i][y_i]=z_i v[xi][yi]=zi,类似二维前缀和,递推可得,v[i][j]+=v[i-1][j]+v[i][j-1]-v[i-1][j-1]
。
有状态转移方程, d p [ i ] [ j ] = v [ i ] [ j ] + max ( d p [ i − 1 ] [ j ] , d p [ i ] [ j − 1 ] ) dp[i][j]=v[i][j]+\max(dp[i-1][j],dp[i][j-1]) dp[i][j]=v[i][j]+max(dp[i−1][j],dp[i][j−1])。
此题 x i , y i x_i,y_i xi,yi 的数据较大,因此需要进行离散化。定义两个数组 X , Y X,Y X,Y,对 x i , y i x_i,y_i xi,yi 离散化。因此 v [ i ] [ j ] v[i][j] v[i][j] 表示,保持 a = X [ i ] , b = Y [ j ] a=X[i],b=Y[j] a=X[i],b=Y[j] 的状态,在将来 m − i − j m-i-j m−i−j 天,每天能获得的分数; d p [ i ] [ j ] dp[i][j] dp[i][j] 表示,当恰好达到 a = X [ i ] , b = Y [ j ] a=X[i],b=Y[j] a=X[i],b=Y[j] 的状态时,能够获得的最高分。
状态转移方程为 d p [ i ] [ j ] = v [ i ] [ j ] + max ( d p [ i − 1 ] [ j ] + ( X [ i ] − X [ i − 1 ] − 1 ) × v [ i − 1 ] [ j ] , d p [ i ] [ j − 1 ] + ( Y [ j ] − Y [ j − 1 ] − 1 ) × v [ i ] [ j − 1 ] ) dp[i][j]=v[i][j]+\max(dp[i-1][j]+(X[i]-X[i-1]-1)\times v[i-1][j],dp[i][j-1]+(Y[j]-Y[j-1]-1)\times v[i][j-1]) dp[i][j]=v[i][j]+max(dp[i−1][j]+(X[i]−X[i−1]−1)×v[i−1][j],dp[i][j−1]+(Y[j]−Y[j−1]−1)×v[i][j−1]),从 X [ i − 1 ] X[i-1] X[i−1] 过渡到 X [ i ] X[i] X[i],有 X [ i ] − X [ i − 1 ] − 1 X[i]-X[i-1]-1 X[i]−X[i−1]−1 天获得的分数为 v [ i − 1 ] [ j ] v[i-1][j] v[i−1][j];从 Y [ j − 1 ] Y[j-1] Y[j−1] 过渡到 Y [ j ] Y[j] Y[j] 同理。
假设 m m m 天结束后的状态为 a = X [ i ] , b = Y [ j ] a=X[i],b=Y[j] a=X[i],b=Y[j],则获得的最高分为, d p [ i ] [ j ] + v [ i ] [ j ] × ( m − X [ i ] − Y [ i ] ) dp[i][j]+v[i][j]\times (m-X[i]-Y[i]) dp[i][j]+v[i][j]×(m−X[i]−Y[i])。因此可以枚举结束后的状态 i , j i,j i,j 得到答案,即 a n s = max 1 ≤ i ≤ c x , 1 ≤ j ≤ c y d p [ i ] [ j ] + v [ i ] [ j ] × ( m − X [ i ] − Y [ i ] ) ans=\max\limits_{1\le i\le cx,1\le j\le cy} dp[i][j]+v[i][j]\times (m-X[i]-Y[i]) ans=1≤i≤cx,1≤j≤cymaxdp[i][j]+v[i][j]×(m−X[i]−Y[i]),其中 c x cx cx 为不同的 x i x_i xi 的个数, c y cy cy 为不同的 y i y_i yi 的个数。
#include
#include
#include
#define N 1002
#define ll long long
using namespace std;
//--------------
//n为奖励的个数。
//m为经历的天数。
int n,m;
//--------------
//-----------------------------------------------------------------
//X,Y为离散化数组。
//v[i][j]表示,保持a=X[i],b=Y[j]的状态,在将来(m-X[i]-Y[j])天,每天能获得的分数。
//dp[i][j]表示,当a=X[i],b=Y[j]时,能够获得的最高分。
ll X[N],Y[N];
ll v[N][N];
ll dp[N][N];
//-----------------------------------------------------------------
//--------------------------------------------------
//reward数组记录奖励的信息,其中x+y>m的奖励不必要记录。
//cnt为可行奖励的个数(对于其中任意一条奖励,有x+y<=m)。
//cx为X离散化后的大小
//cy为Y离散化后的大小
struct node
{
ll x;
ll y;
ll z;
}reward[N];
int cnt,cx,cy;
//--------------------------------------------------
int main()
{
cin>>n>>m;
int i,j;
for(i=1;i<=n;i++)
{
ll x,y,z;
scanf("%lld%lld%lld",&x,&y,&z);
if(x+y>m) continue;//忽略
reward[++cnt]=node{x,y,z};
X[++cx]=x;
Y[++cy]=y;
}
//-------------------------------
//排序,去重。
sort(X+1,X+1+cx);
cx=unique(X+1,X+1+cx)-X-1;
sort(Y+1,Y+1+cy);
cy=unique(Y+1,Y+1+cy)-Y-1;
//-------------------------------
//-----------------------------------------------
//初始化。
for(i=1;i<=n;i++)
{
int I=lower_bound(X+1,X+1+cx,reward[i].x)-X;
int J=lower_bound(Y+1,Y+1+cy,reward[i].y)-Y;
v[I][J]+=reward[i].z;//注意"+="
}
//------------------------------------------------
//------------------------------------------------
//二维前缀和维护v[i][j]
for(i=1;i<=cx;i++)
{
for(j=1;j<=cy;j++)
{
v[i][j]+=v[i-1][j]+v[i][j-1]-v[i-1][j-1];
}
}
//------------------------------------------------
//-------------------------------------------------------------------------------------------------------
//递推dp[i][j]。
for(i=1;i<=cx;i++)
{
for(j=1;j<=cy;j++)
{
dp[i][j]=v[i][j]+max(dp[i-1][j]+(X[i]-X[i-1]-1)*v[i-1][j],dp[i][j-1]+(Y[j]-Y[j-1]-1)*v[i][j-1]);
}
}
//--------------------------------------------------------------------------------------------------------
//---------------------------------------------------------
//假设最终状态为a=X[i],b=Y[j],更新答案。
ll ans=0;
for(i=1;i<=cx;i++)
{
for(j=1;j<=cy;j++)
{
if(X[i]+Y[j]>m) continue;
ans=max(ans,dp[i][j]+(ll)(m-X[i]-Y[j])*v[i][j]);
}
}
//---------------------------------------------------------
cout<<ans<<endl;
return 0;
}