【Luogu P6473】【NOI Online】未了

未 了 未了


L u o g u P 6473 Luogu P6473 LuoguP6473


题目描述

由于触犯天神,Sisyphus 将要接受惩罚。

宙斯命 Sisyphus 推一块巨石上长度为 L 的山坡。Sisyphus 匀速向上推的速度为每年 vv 的长度(由于是匀速,故经过 1/2年将能向

上推 v/2 的长度)。然而,宙斯并不希望 Sisyphus 太快到达山顶。宙斯可以施展 n 个魔法,若宙斯施展第 i 个魔法 (1≤i≤n),则当

Sisyphus 第一次到达位置 a i 时,他将会同巨石一起滚落下山底,并从头推起。(滚落的时间忽略不计,即可看作第一次到达位

置 a i 后 Sisyphus 立即从山底重新出发)

例如宙斯施用了 a i = 3 和 a i = 5 的两个魔法。Sisyphus 的速度 v=1 ,山坡的长度 L=6,则他推石上山过程如下:

用 3 年走到位置 3。受 a i = 3 的魔法影响,回到了山底出发。

再用 3 年走到位置 3,然而因为是第二次到达,a i = 3 的魔法不起作用。

用 2 年走到位置 5。受 a i = 5 的魔法影响,回到了山底出发。

用 6 年从山底走到了山顶。花费的总时间为 14 年。

现在,宙斯有 q 个询问。对于第 i 个询问 t i

宙斯想知道,他最少需要施展多少个魔法才能使 Sisyphus 到达山顶所用的年数大于 t i


输入格式

第一行三个整数 n , L , v 分别表示魔法的种类数,山坡的长度,Sisyphus 的速度。

第二行 n 个整数。第 i 个整数 a i表示第 i 个魔法作用的位置。(1

第三行一个整数 q 表示宙斯的询问个数。

接下来 q 行每行一个整数,第 i 行的整数 t i

表示宙斯的第 i 个询问。(1

输出格式

输出 q 行,每行恰好一个整数,第 i 行的整数对应第 i 个询问的答案 (1≤i≤q)

如果宙斯无论如何都不能使 Sisyphus 使用的年数大于 t i,请输出 −1。


输入输出样例

输入

3 6 3
3 5 1
4
1
3
4
5

输出

0
1
2
-1

说明/提示

  • 不使用任何魔法,Sisyphus 需要 2 年走上山顶

  • 使用魔法 2 ,Sisyphus 需要 11 / 3年走上山顶(用时 3 / 5年走到魔法 2 的位置并滚落下山,再用时 6 / 3 = 2 年走到山顶)

  • 使用魔法 1,2 ,Sisyphus 需要 14 / 3年走上山顶

  • 宙斯不能使 Sisyphus 用大于 5 年的时间走上山顶

  • 对于测试点 1 ∼ 8 : n = 1

  • 对于测试点 9 ∼ 12 : n = 2

  • 对于测试点 13 ∼ 17 : n,q ≤ 1000

  • 对于所有测试点:1 ≤ n , q ≤ 2×10 ^ 5 ,1≤v≤L≤10 ^ 9,1≤a i < L,1 ≤ t i ≤ 10 ^ 9

  • 数据保证 a i 两两不同

解题思路

这题用的是二分,先把魔法排一边序再求前缀和,最后·再来二分来求答案即可

程序如下

#include
#include
#include
#include
#define ll long long 
using namespace std;
ll n,m, v, L, l, r, mid, s, t, a[200010];
bool cmp(ll x, ll y)
{
	return x > y;
}
int main()
{
	scanf("%d%d%d", &n, &L, &v);
	for (ll i = 1; i <= n; ++i)
		scanf("%d", &a[i]);
	sort(a+1, a+1+n,cmp);//排序
	for (ll i =1; i<= n ; ++i)
		a[i] += a[i - 1];//前缀和
	scanf("%d", &m);
	for (ll i =1; i <= m; ++i)
	{
		scanf("%d", &t);
		s = t*v;
		if (a[n] + L <= s) //如果小于就直接输出-1
		{
			printf("-1\n");
			continue;
		}
		l = 0;
		r = n;
		while(l < r)
		{
			mid = (l + r)/2;
			if (a[mid] + L < s) l = mid + 1;
			else r = mid;
		}//二分模板
		printf("%d\n", l);
	}
}

你可能感兴趣的:(二分)