题意:
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;
}