牛客竞赛 NC19809 Growth

欢迎访问个人博客

传送门 ↬ \looparrowright

题目描述

  弱弱有两个属性 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 axi b ≥ y i b≥ y_i byi,则弱弱在接下来的每一天都可以得到 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) (1n1000,1m2000000000)
  接下来 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) (1xi,yi1000000000,1zi1000000)

输出描述

  一行一个整数表示答案。

示例1

输入
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=ib=j 的状态,在将来 m − i − j m-i-j mij 天,每天能获得的分数。定义 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[i1][j],dp[i][j1])
  此题 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 mij 天,每天能获得的分数; 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[i1][j]+(X[i]X[i1]1)×v[i1][j],dp[i][j1]+(Y[j]Y[j1]1)×v[i][j1]),从 X [ i − 1 ] X[i-1] X[i1] 过渡到 X [ i ] X[i] X[i],有 X [ i ] − X [ i − 1 ] − 1 X[i]-X[i-1]-1 X[i]X[i1]1 天获得的分数为 v [ i − 1 ] [ j ] v[i-1][j] v[i1][j];从 Y [ j − 1 ] Y[j-1] Y[j1] 过渡到 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]×(mX[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=1icx,1jcymaxdp[i][j]+v[i][j]×(mX[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;
}

你可能感兴趣的:(题解)