未 了 未了 未了
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<i<n)
第三行一个整数 q 表示宙斯的询问个数。
接下来 q 行每行一个整数,第 i 行的整数 t i
表示宙斯的第 i 个询问。(1<i<n)
输出格式
输出 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<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#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);
}
}