20201029CSP提高组训练(走亲戚)
走亲戚
题目
题目描述
小X家大年初三要去拜访同村的所有亲戚,恰好他家的所有亲戚都住在一条东西走向的公路边,而车的油量有限,车 子油量能行驶的距离为L,他对n个亲戚随机进行编号(1,2...n),假设马路的中点为0,某个亲戚的坐标xi就为该亲 戚到马路中点的距离(设中点以东的坐标为正数),而小X决定按照一个规则去拜访亲戚们:
(1)先向东走,去东边能抵达的最远亲戚家。
(2)如果油量足够,再向西走,去西边能抵达的最远亲戚家。
如此往复,直到油量不足以到下一家亲戚时,留在当前这家过夜。
现在给定n个亲戚的位置坐标,m个出门状态(以第ai个亲戚家作为出发点,车内油量为li),请你判断下小X会在哪 个亲戚家过夜。
输入格式
单组测试数据。
第一行包含两个整数n 和 m (1 ≤ n, m ≤ 2*10^5),表示亲戚的数目以及出门状态的数目。
接下来一行包含n个整数 x1, x2, ..., xn ( -10^9 ≤ xi ≤ 10^9),表示每个亲戚的位置坐标。保证输入的亲戚的位置坐 标两两不相同。
接下来m行给出查询。每行给出ai (1 ≤ ai ≤ n) 和 li(1 ≤ li ≤ 10^9),表示出门时,小X在第ai个亲戚家,车上油量 是li。
输出格式
输出m行,第i行输出第i个出门状态时的小X最终在哪个亲戚家过夜。
输入输出样例
输入 #1
3 2
0 3 -2
2 3
1 8
输出 #1
1
3
输入 #2
5 2
-3 2 5 6 -7
2 20
1 16
输出 #2
5
3
输入 #3
8 2
-1 -2 -3 3 -6 -7 -9 8
1 15
2 9
输出 #3
4
1
说明/提示
数据范围
对于15%的数据, -100 ≤ xi ≤ 100 对于30%的数据,1 ≤ n,m ≤ 10 对于100%的数据,1 ≤ n, m ≤ 2*10^5 ,-10^9 ≤ xi ≤ 10^9, 1 ≤ li ≤ 10^9
样例解释
样例一: 一共有n=3个亲戚编号为1,2,3,位置分别是{0,3,-2},有m=2种可能的出发状态, 经过排序可知实际位置分布为{-2,0,3},分别代表了编号3,1,2的位置
第一种情况(从编号为2的亲戚家出发,车上油量为3),此时东边已经没有亲戚可以拜访,所以从西边找到最远能 拜访的1,到达编号1亲戚家时油量刚好耗尽,则小X会留在1号家过夜
第二种情况(从1号亲戚家出发,车上油量为8),先往东去最远的2号的亲戚家,油量消耗3后抵达,油量剩余5。 然后往西去编号为3的亲戚家,油量消耗5后抵达,油量剩余0,此时油量不足以继续去拜访东边的下一家,则小X会 留在3家过夜
补充样例
input:
4 4
-1000000000 0 1 1000000000
2 999999999
2 999999999
2 999999999
2 999999998
output:
3
3
3
2
思路
认为是这次比赛最水的一道题,直接用二分模拟即可
但是也会出现像以上补充样例的情况,这是没有优化的程序就会被卡飞,因此我们考虑批量处理:
当经过一轮(先向东后向西)模拟后,若位置没变,我们记向东能走的最远的点为r,模拟前的位置为pre,gas为当前汽油量,直接让gas对r和pre的距离取模即可,但要注意(gas/dist(r,pre))的奇偶性,决定取模后是在r位置还是pre位置
代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#define rr register
#define nn 200010
using namespace std;
int read(){
int re = 0 , sig = 1;
char c = getchar();
while(c < '0' || c > '9'){
if(c == '-')sig = -1;
c = getchar();
}
while(c >= '0' && c <= '9')re = (re << 1) + (re << 3) + c - '0' , c = getchar();
return re * sig;
}
struct node{
int pos , id;
}a[nn];
bool cmp(node a , node b){
return a.pos < b.pos;
}
void output(int x){
if(x >= 10)output(x / 10);
putchar(x % 10 + '0');
}
int n , m;
int pos[nn];
int dict[nn];
int main(){
n = read(); m = read();
for(rr int i = 1 ; i <= n ; i++){
pos[i] = a[i].pos = read();
a[i].id = i;
}
sort(a + 1 , a + n + 1 , cmp);
for(rr int i = 1 ; i <= n ; i++)
dict[a[i].id] = i;
rr int dist = a[n].pos - a[1].pos;
for(rr int i = 1 ; i <= m ; i++){
rr int p , gas;
p = read(); gas = read();
if(dist == 0){
output(p);
putchar('\n');
continue;
}
p = dict[p];
if(a[n].pos - a[p].pos <= gas)
gas -= a[n].pos - a[p].pos , p = n;
if((gas / dist) & 1) p = 1;
gas %= dist;
// cout << p << '\t' << gas << endl;
rr int l , r , mid;
rr int tmp;
rr int pre , delta , _r;
do{
tmp = gas;
l = p , r = n;
pre = p;
while(l < r){
mid = (l + r) / 2;
if((l + r) & 1)++mid;
if(a[mid].pos - a[p].pos <= gas) l = mid;
else r = mid - 1;
}
gas -= a[l].pos - a[p].pos;
_r = p = l;
r = l , l = 1;
while(l < r){
mid = (l + r) / 2;
if(a[p].pos - a[mid].pos <= gas) r = mid;
else l = mid + 1;
}
gas -= a[p].pos - a[l].pos;
p = l;
delta = a[_r].pos - a[pre].pos;
if(delta != 0 && p == pre){
if((gas / delta) & 1)p = _r;
gas %= delta;
}
}
while(tmp != gas);
output(a[l].id);
putchar('\n');
// cout << gas << "!!!\n";
}
return 0;
}