51nod旋转绳 1467

题意:

1467 旋转绳
1.5 秒 131,072.0 KB 80 分 5级题
平面上有n个钉子,他们从1到n编号,第i个钉子的坐标是 (xi, 0)。然后我们我们把一个长度为L,带重物的绳子系到第i个钉子上(那么重物所在的坐标是(xi, -L))。然后用力将重物向右推,开始逆时针旋转。同时,如果旋转的过程中碰到其它的钉子,就会绕着那个钉子旋转。假设每个钉子都很细,重物绕着它旋转时,不影响到绳子的长度。
在这里插入图片描述
更一般的,如果绳子碰到多个钉子,那么它会绕着最远的那个钉子转。特殊的,如果绳子的末端碰到了一个钉子,那么也会绕着那个钉子以长度为0的绳子在转。

经过一段时间之后,重物就会一直绕着某个钉子转。

现在有m个查询,每个查询给出初始的绳子长度以及挂在哪个钉子下旋转,请找出重物最终会绕哪个钉子旋转。

样例解释:

在这里插入图片描述

输入
单组测试数据。
第一行包含两个整数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),表示该查询的重物挂在第ai个钉子上,绳子长度是li。
输出
输出m行,第i行输出第i个查询的重物最终绕着哪个钉子转。
输入样例
3 2
0 3 5
2 3
1 8
输出样例
3
2

思路:

这道题也是很明显的二分,但是由于本菜鸡也是十分的菜,就给写挫了5555

(1)首先,肯定要二分,康康最后挂在了哪个钉子上,排过序的钉子的编号和排序前还不太一样,这是个坑,但是我写的时候果断跳进去了。。

(2)往左边转和往右边转是两种情况,所以要分开考虑💭

(3)如果在两个钉子之间循环,那么y就要取模,否则会T掉或wa掉

(4)最后就是注意stdio.h,换句话说就是卡IO了。二分的时候要对res进行初始化,否则会跑死的!!!

代码实现:

#include<stdio.h>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;

int n,m;
struct node{
	int x;
	int id;
}G[maxn];
int pos[maxn];

template <class T>
inline bool scan_d(T &ret){//输入外挂
	char c;
	int sgn;
	if(c = getchar(),c == EOF){
		return 0;
	}
	while(c != '-'&&(c < '0'||c > '9')){
		c = getchar();
	}
	sgn = (c == '-') ? -1 : 1;
	ret = (c == '-') ? 0: (c - '0');
	while(c = getchar(),c >= '0'&&c <= '9'){
		ret = ret * 10 + (c - '0');
	}
	ret *= sgn;
	return 1;
}

template <class T>
inline void out_d(T a){//输出外挂
	if(a < 0){
		putchar('-');
		a  = -a;
	}
	if(a >= 10){
		out_d(a / 10);
	}
	putchar(a % 10 + '0');
}

bool cmp(node a,node b){//x从小到大排序啊
	return a.x < b.x;
}

int bs(int u){//二分
	int l = 1; int r = n + 1; int res = n + 1;//注意res进行初始化
	while(l <= r){
		int mid = (l + r) >> 1;
		if(G[mid].x > u){
			res = mid;
			r = mid - 1;
		}
		else l = mid + 1;
	}
	return res;
}

int main(){
	scanf("%d%d",&n,&m);
	for(int i = 1;i <= n;i++){
		scanf("%d",&G[i].x);
		G[i].id = i;//因为要输出的是排序前在第几颗钉子上
	}
	sort(G + 1,G + 1 + n,cmp);
	for(int i = 1;i <= n;i++){
		pos[G[i].id] = i;//记录原来在G[i].id位置的钉子,现在在哪个位置
	}
	int x,flag,now,len;
	for(int i = 1;i <= m;i++){
		scanf("%d%d",&x,&len);
		x = pos[x];
		flag = 1;//和我原来分奇偶效果是一样的
		now = bs(len+G[x].x) - 1;
		len = len - (G[now].x - G[x].x);
		flag = -1;
		int pre = x;
		x = now;
		while(len){
			if(flag == 1){
				now = bs(len + G[x].x) - 1;
			}
			else{
				now = bs(G[x].x - len);
				if(now&&G[now - 1].x == G[x].x - len) now--;
			}
			if(now == x) break;
			int y = abs(G[now].x - G[x].x);
			if((len / y) % 2 == 1){
				x = now;
				flag = -flag;
			}
			len = len - y;
		}
		printf("%d\n",G[x].id);
	}
	return 0;
}

我的错误代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;

int n,m;
int x[maxn];
struct node{
	int a;
	int l;
}G[maxn];

int main(){
	scanf("%d%d",&n,&m);
	for(int i = 1;i <= n;i++){
		scanf("%d",&x[i]);
	}
	sort(x + 1,x + 1 + n);
	for(int i = 1;i <= m;i++){
		scanf("%d%d",&G[i].a,&G[i].l);
	}
	for(int i = 1;i <= m;i++){
		int now = G[i].a;
		int cnt = 0;
		while(G[i].l >= 0){
			cnt++;
			int L,id;
			if(cnt % 2 == 1){
				L = x[now] + G[i].l;
				id = lower_bound(x + now,x + 1 + n,L) - x;
				if(id == n + 1||x[id] > L) id--;
				G[i].l = L - x[id];
			}
			else{
				L = x[now] - G[i].l;
				id = lower_bound(x + 1,x + 1 + now,L) - x;
				G[i].l = abs(L - x[id]);
			}
			if(id == now) break;
			now = id;
		}
		printf("%d\n",now);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值