来源:

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 1048576K,其他语言2097152K
64bit IO Format: %lld

题目描述

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

输出描述:
一行一个整数表示答案。
示例1
输入
复制

2 4
2 1 10
1 2 20

输出
复制

50

备注:

在样例中,弱弱可以这样规划:第一天a涨1,第二天b涨1,第三天b涨1,第四天a涨1。 共获得0+0+20+30=50分。

题解:

dp [ i ] [ j ]表示在sum = i+j天,两种属性分别是i和j所得到的分数(一共)
根据题意可得:
dp[i][j]=max(dp[i-1][j],dp[i][j-1])+a[i][j]
a[i][j]表示属性分别是i和j可获得大分数(当天)
那a[i][j]是怎么得到的?
我们用二维前缀和的思想来实现:
a[ xi ][ xj ]=z
a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1]
整合一下最后答案就是:
dp[i][j]=max(dp[i-1][j],dp[i][j-1])+a[i][j]
ans=max(ans,dp[i][j]+(m-i-j)*a[i][j])
如果我们在这一天可以获得a[][]的分数,那之后的每一天都可以获得,在此之后还有(m-i-j)天,所以直接加上这个分数在以后天数获得的总和
本题的xi,yi,m都比较大记得要先离散化。

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1400;
int dp[maxn][maxn];
int a[maxn][maxn];
int x[maxn],y[maxn],z[maxn];
int b[maxn],c[maxn];
int main()
{
   
	int sum=0;
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
   
		cin>>x[i]>>y[i]>>z[i];
		b[i]=x[i];
		c[i]=y[i];
	}
	sort(b+1,b+1+n);
	sort(c+1,c+1+n);
	int ant1=unique(b+1,b+1+n)-b-1;
	int ant2=unique(c+1,c+1+n)-c-1;
	for(int i=1;i<=n;i++)
	{
   
		x[i] = lower_bound(b+1,b+1+ant1,x[i])-b;
        y[i] = lower_bound(c+1,c+1+ant2,y[i])-c;
        a[x[i]][y[i]] += z[i];
	}
	for(int i=1;i<=ant1;i++)
	for(int j=1;j<=ant2;j++)
	{
   
		a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1];
	}
	for(int i=1;i<=ant1;i++)
	for(int j=1;j<=ant2;j++)
        {
   
            dp[i][j] = max(dp[i-1][j]+(b[i]-b[i-1]-1)*a[i-1][j],dp[i][j-1]+(c[j]-c[j-1]-1)*a[i][j-1]) + a[i][j];
        }
    for(int i=1;i<=ant1;i++)
	for(int j=1;j<=ant2;j++)
	{
   
		if(b[i]+c[i]>m)break;
		sum=max(sum,dp[i][j]+(m-b[i]-c[i])*a[i][j]);
		cout<<sum<<endl;
	}
	cout<<sum;
	return 0;
    
}