2018 ccpc camp day 1 E. Growth [ 离散化 + dp ]

                                         Problem E. Growth

题解:

 艰难的补题中...题目中m,x,y都很大,但是n只有1000,所以就将x,y离散化(因为递增可以算是跨越式的);把奖励的x拿出来从小到大排序,得到。把奖励的y拿出来从小到大排序,得到

表示 a 值到达,b 值达到时接下来每天可以得到的奖励。

其中为满足(  )的可得到奖励的总和,反过来就是找最小的大于等于原先的()的(  )。

表示 a 值达到,b 值达到时已经拿到的奖励的最大值。

状态转移方程:

最后统计一下答案就可以了。

代码:

/*
*2018/8/15 ccpc camp day1 E Growth
*Growth:
*把奖励的x拿出来从小到大排序,得到x1,x2,...,xn。
*把奖励的y拿出来从小到大排序,得到y1,y2,...,yn。
*用v[i][j]表示a值到达xi,b值达到yi时接下来每天可以得到的奖励。
*v[i][j] = v[i - 1][j] + v[i][j - 1] - v[i - 1][j - 1] + t[i][j];
*其中t[i][j]为满足xi,yj的可能得到奖励的总和, 就是小于等于(xi, yi)。
*用f[i][j]表示a值达到xi,b值达到yj时已经拿到的奖励的最大值。
*f[i-1][j] + (x[i] - x[i-1] - 1) * v[i-1][j] + v[i][j] -> f[i][j]
*f[i][j-1] + (y[j] - y[j-1] - 1) * v[i][j-1] + v[i][j] -> f[i][j]
*最后统计一下答案就可以了。
*/


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<set>
#define ll long long

using namespace std;
const int maxn = 1e3+7;

int numa, numb;
ll n, m, dp[maxn][maxn], v[maxn][maxn], x[maxn], y[maxn], z[maxn], a[maxn], b[maxn];
set<ll> st;

void init()
{
	memset(dp, 0, sizeof(dp));
	memset(v, 0, sizeof(v));
	numa = 0; numb = 0;
	st.clear();
}


int main() {
	while(scanf("%lld%lld", &n,&m) != EOF)
	{
		init();
		for(int i = 1; i <= n; i++) scanf("%lld%lld%lld", &x[i], &y[i], &z[i]);
		
		for(int i = 1; i <= n; i++)
			if(st.count(x[i]) == 0) {
				a[++numa] = x[i];
				st.insert(x[i]);
			}
		st.clear();
		for(int i = 1; i <= n; i++)
			if(st.count(y[i]) == 0) {
				b[++numb] = y[i];
				st.insert(y[i]);
			}
		
		sort(a + 1, a + numa + 1);
		sort(b + 1, b + numb + 1);
		
		
		for(int i = 1; i <= n; i++) {
            int v1 = lower_bound(a + 1, a + 1 + numa, x[i]) - a;
            int v2 = lower_bound(b + 1, b + 1 + numb, y[i]) - b;
            v[v1][v2] += z[i];
        }
        
       
		for(int i = 1; i <= numa; i++)
			for(int j = 1; j <= numb; j++)
				v[i][j] += (v[i-1][j] + v[i][j-1] - v[i-1][j-1]);


		for(int i = 1; i <= numa; i++)
			for(int j = 1; j <= numb; j++)
				dp[i][j] = max(dp[i-1][j] + (a[i] - a[i-1] - 1)*v[i-1][j], dp[i][j-1] + (b[j] - b[j-1] - 1)*v[i][j-1]) + v[i][j];
		ll ans = 0;
		for(int i = 1; i <= numa; i++)
			for(int j = 1; j <= numb; j++)
				if(a[i] + b[j] <= m) ans = max(ans, dp[i][j] + v[i][j]*(m - a[i] - b[j]));
		
		printf("%lld\n", ans);
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值