1467 旋转绳
题目来源: CodeForces
基准时间限制:1.5 秒 空间限制:131072 KB 分值: 80 难度:5级算法题
平面上有n个钉子,他们从1到n编号,第i个钉子的坐标是 (xi, 0)。然后我们我们把一个长度为L,带重物的绳子系到第i个钉子上(那么重物所在的坐标是(xi, -L))。然后用力将重物向右推,开始逆时针旋转。同时,如果旋转的过程中碰到其它的钉子,就会绕着那个钉子旋转。假设每个钉子都很细,重物绕着它旋转时,不影响到绳子的长度。
![](http://img.51nod.com/upload/000FBEE8/08D287CCFBCC7FAB0000000000000034.jpeg)
更一般的,如果绳子碰到多个钉子,那么它会绕着最远的那个钉子转。特殊的,如果绳子的末端碰到了一个钉子,那么也会绕着那个钉子以长度为0的绳子在转。
经过一段时间之后,重物就会一直绕着某个钉子转。
现在有m个查询,每个查询给出初始的绳子长度以及挂在哪个钉子下旋转,请找出重物最终会绕哪个钉子旋转。
样例解释:
![](http://img.51nod.com/upload/000FBEE8/08D287CECF17F099000000000000003A.jpeg)
Input
单组测试数据。
第一行包含两个整数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。
Output
输出m行,第i行输出第i个查询的重物最终绕着哪个钉子转。
Input示例
3 2
0 3 5
2 3
1 8
Output示例
3
2
System Message (题目提供者)
C++的运行时限为:1500 ms ,空间限制为:131072 KB 示例及语言说明请按这里
Analysis分析
模拟+二分优化
显然,如果绳端在这个时候没法接触到某一个钉子,当它绕回去再绕回来以后,仍然没法接触到那根钉子
二分的范围是前缀和,两个方向要分开计算
既然是前缀和,那么在计算的时候需要将绳子也模拟成前缀和的形式,即剩余绳长 + 钉子所对应前缀和
然后看是不是可以在两个钉子上多绕几圈(即取模)
第一个坑点:钉子编号不按坐标增序(然而对钉子坐标是要排序的)
第二个坑点:当两边边界的钉子都是近乎无限远的时候,需要判断是否可以在非边界钉子上快速绕圈(比如第七个点)
(当然这可能只卡我的写法)
第三个...坑点:记得 stdio.h
Code代码
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<stdio.h> 2 #include<algorithm> 3 #include<iostream> 4 using namespace std; 5 6 long long trans[1000000],LtoR[1000000],RtoL[1000000]; 7 int n,m; 8 int Time = 0; 9 10 struct data{ 11 long long val,ord; 12 }arr[1000000]; 13 14 bool cmp(const data &a,const data &b){ 15 return a.val < b.val; 16 } 17 18 int L_find(long long x){ 19 int L = 1,R = n,mid; 20 while(L < R){ 21 mid = (L+R+1)/2; 22 if(LtoR[mid] <= x) L = mid; 23 else R = mid-1; 24 }return L; 25 } 26 27 int R_find(long long x){ 28 int L = 1,R = n,mid; 29 while(L < R){ 30 mid = (L+R)/2; 31 if(RtoL[mid] <= x) R = mid; 32 else L = mid+1; 33 }return L; 34 } 35 36 int rotate_toR(int &pos,long long &L){ 37 L += LtoR[pos]; 38 int tar = L_find(L); 39 if(pos != 1 && arr[tar].val-arr[pos-1].val > L-LtoR[tar] && arr[tar].val-arr[pos].val) 40 L = (L-LtoR[tar])%(2*(arr[tar].val-arr[pos].val))+LtoR[tar]; 41 L -= LtoR[tar]; 42 // printf("CheckPoint A: tar%d L%d\n",tar,L); 43 if(LtoR[tar] && L > LtoR[tar]*2) L %= LtoR[tar]*2; 44 // printf("CheckPoint AA: tar%d L%d\n",tar,L); 45 // if(!L){ pos = tar; return 1; } 46 pos = tar; 47 return 1; // Then keep dir 48 } 49 50 int rotate_toL(int &pos,long long &L){ 51 L += RtoL[pos]; 52 int tar = R_find(L); 53 if(pos != n && arr[pos+1].val-arr[tar].val > L-RtoL[tar] && arr[pos].val-arr[tar].val) 54 L = (L-RtoL[tar])%(2*(arr[pos].val-arr[tar].val))+RtoL[tar]; 55 L -= RtoL[tar]; 56 if(RtoL[tar] && L > RtoL[tar]*2) L %= RtoL[tar]*2; 57 // printf("CheckPoint B: tar%d L%d\n",tar,L); 58 // if(!L){ pos = tar; return 1; } 59 pos = tar; 60 return 0; // Then keep dir 61 } 62 63 long long readll(){ 64 long long ret = 0; char ctr = getchar(); 65 while(ctr < '0' || ctr > '9') ctr = getchar(); 66 while(ctr >= '0' && ctr <= '9') ret = ret*10+ctr-'0',ctr = getchar(); 67 return ret; 68 } 69 70 int read(){ 71 int ret = 0; char ctr = getchar(); 72 while(ctr < '0' || ctr > '9') ctr = getchar(); 73 while(ctr >= '0' && ctr <= '9') ret = ret*10+ctr-'0',ctr = getchar(); 74 return ret; 75 } 76 77 int main(){ 78 scanf("%d%d",&n,&m); 79 // n = read(),m = read(); 80 81 for(int i = 1;i <= n;i++){ 82 scanf("%lld",&arr[i].val); 83 // arr[i].val = readll(); 84 arr[i].ord = i; 85 } 86 87 sort(arr+1,arr+1+n,cmp); 88 89 for(int i = 1;i <= n;i++) 90 trans[arr[i].ord] = i; 91 92 LtoR[1] = 0; 93 for(int i = 2;i <= n;i++) 94 LtoR[i] = LtoR[i-1]+arr[i].val-arr[i-1].val; 95 RtoL[n] = 0; 96 for(int i = n-1;i >= 1;i--) 97 RtoL[i] = RtoL[i+1]+arr[i+1].val-arr[i].val; 98 99 // for(int i = 1;i <= n;i++) printf("%d ",LtoR[i]); cout << endl; 100 101 while(m--){ 102 int pos = 0; long long L = 0; 103 scanf("%d%lld",&pos,&L); 104 // pos = read(), L = readll(); 105 106 pos = trans[pos]; 107 108 int times = 0,dir = 0; 109 while(times < 2){ 110 int last = pos; 111 // cout << "CTime: " << Time++ << " Pos " << pos << " L " << L << endl; 112 if(!dir) dir = rotate_toR(pos,L); 113 else dir = rotate_toL(pos,L); 114 115 if((pos+1 > n || L < arr[pos+1].val-arr[pos].val) && (pos-1 < 1 || L < arr[pos].val-arr[pos-1].val)) times = 2; 116 117 // if(pos == last) times++; 118 // else times = 0; 119 // cout << "Time: " << Time++ << endl; 120 }printf("%d\n",arr[pos].ord); 121 } 122 123 return 0; 124 }