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('
');
			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 << '	' << 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('
');
//		cout << gas << "!!!
";
	}
	return 0;
} 

作业


年会小游戏


公司搬迁


原文地址:https://www.cnblogs.com/dream1024/p/13957660.html