题目链接:http://acm.ocrosoft.com/problem.php?cid=1627&pid=15

题目描述:

跳房子,也叫跳飞机,是一种世界性的儿童游戏,也是中国民间传统的体育游戏之一。

跳房子的游戏规则如下:

在地面上确定一个起点,然后在起点右侧画 nn 个格子,这些格子都在同一条直线上。每个格子内有一个数字(整数),表示到达这个 格子能得到的分数。玩家第一次从起点开始向右跳,跳到起点右侧的一个格子内。第二次再从当前位置继续向右跳,依此类推。规则规定:

玩家每次都必须跳到当前位置右侧的一个格子内。玩家可以在任意时刻结束游戏,获得的分数为曾经到达过的格子中的数字之和。

现在小 RR 研发了一款弹跳机器人来参加这个游戏。但是这个机器人有一个非常严重的缺陷,它每次向右弹跳的距离只能为固定的 dd 。小 RR 希望改进他的机器人,如果他花 gg 个金币改进他的机器人,那么他的机器人灵活性就能增加 gg ,但是需要注意的是,每 次弹跳的距离至少为 11 。具体而言,当 g<dg<d 时,他的机器人每次可以选择向右弹跳的距离为 d-g,d-g+1,d-g+2dg,dg+1,dg+2 ,…, d+g-2d+g2 , d+g-1d+g1 , d+gd+g ;否则(当 g \geq dgd时),他的机器人每次可以选择向右弹跳的距离为 11 , 22 , 33 ,…, d+g-2d+g2 , d+g-1d+g1 , d+gd+g 

现在小 RR 希望获得至少 kk 分,请问他至少要花多少金币来改造他的机器人。

输入输出格式

输入格式:
 

第一行三个正整数 nn , dd , kk ,分别表示格子的数目,改进前机器***跳的固定距离,以及希望至少获得的分数。相邻两个数 之间用一个空格隔开。

接下来 nn 行,每行两个正整数 x_i,s_ixi,si ,分别表示起点到第 ii 个格子的距离以及第 ii 个格子的分数。两个数之间用一个空格隔开。保证 x_ixi 按递增顺序输入。

输出格式:
 

共一行,一个整数,表示至少要花多少金币来改造他的机器人。若无论如何他都无法获得至少 kk 分,输出 -1−1 

输入输出样例

输入样例#1: 

7 4 10
2 6
5 -3
10 3
11 -3
13 1
17 6
20 2

输出样例#1

2

输入样例#2:

7 4 20
2 6
5 -3
10 3
11 -3
13 1
17 6
20 2

输出样例#2

-1

说明

【输入输出样例 1 说明】 22个金币改进后, 小 R 的机器人依次选择的向右弹跳的距离分别为2, 3, 5, 3, 4,32,3,5,3,4,3, 先后到达的位置分别为 2, 5, 10, 13, 17, 202,5,10,13,17,20, 对应1, 2, 3, 5, 6, 71,2,3,5,6,7 66 个格子。这些格子中的数字之和1515 即为小 R 获得的分数。

输入输出样例 2 说明

由于样例中 77 个格子组合的最大可能数字之和只有 1818 ,无论如何都无法获得2020

数据规模与约定

本题共 10 组测试数据,每组数据 10 分。

对于全部的数据满足1 ≤ n ≤ 500000, 1 ≤ d ≤2000, 1 ≤ x_i, k ≤ 10^9, |s_i| < 10^51n500000,1d2000,1xi,k109,si<105

对于第 1, 21,2组测试数据, n ≤ 10n10

对于第3, 4, 53,4,5 组测试数据, n ≤ 500n500

对于第6, 7, 86,7,8 组测试数据, d = 1d=1

思路:动态规划+二分法优化,设dp[i]表示跳到第i格的最高得分,那么,dp[i]肯定是从它前面那些能够跳到的格子里面得分最高的那个格子跳过来的,可以从i号格子前面第一个格子开始查找得分最高的格子,直到超过最大可跳范围为止,把这个区间的最大得分加上自己本身的分数就是第i格的最高分数了。

 

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll n, d, k;
ll dp[500005];
struct gezi
{
	ll pos;//记录位置
	ll zhi;//记录该位置的值
}a[500005];
bool check(int m)
{
	ll maxx = d + m;//最远距离
	ll minn = d - m;//最近距离
	if (minn <= 0)minn = 1;//最近记录为负则赋值为1
	memset(dp, -128, sizeof(dp));//初始化一个很小的值,不能少!!!!!
	dp[0] = 0;
	for (int i = 1; i <= n; i++)
	{
		for (int j = i - 1; j >= 0; j--)
		{
			if (a[i].pos - a[j].pos < minn)continue;
			if (a[i].pos - a[j].pos > maxx)break;
			dp[i] = max(dp[i], dp[j] + a[i].zhi);
			if (dp[i] >= k)
			{
				return 1;
			}
		}
	}
	return 0;
}
int main()
{
	cin >> n >> d >> k;
	int sum = 0;
	int ans = -1;
	a[0].pos = 0;
	a[0].zhi = 0;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i].pos >> a[i].zhi;
		if (a[i].zhi > 0)
		{
			sum += a[i].zhi;
		}
	}
	int l = 0, r = 1005;//二分优化
	int mid;
	while (l < r)
	{
		mid = (l + r) / 2;
		if (check(mid))
		{
			r = mid;
			ans = r;
		}
		else
		{
			l = mid + 1;
		}
	}
	cout << ans << endl;
}