[51nod] 1467 旋转绳

Posted Lev今天学习了吗

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[51nod] 1467 旋转绳相关的知识,希望对你有一定的参考价值。

1467 旋转绳

题目来源: CodeForces 基准时间限制:1.5 秒 空间限制:131072 KB 分值: 80 难度:5级算法题

平面上有n个钉子,他们从1到n编号,第i个钉子的坐标是 (xi, 0)。然后我们我们把一个长度为L,带重物的绳子系到第i个钉子上(那么重物所在的坐标是(xi, -L))。然后用力将重物向右推,开始逆时针旋转。同时,如果旋转的过程中碰到其它的钉子,就会绕着那个钉子旋转。假设每个钉子都很细,重物绕着它旋转时,不影响到绳子的长度。

技术分享

更一般的,如果绳子碰到多个钉子,那么它会绕着最远的那个钉子转。特殊的,如果绳子的末端碰到了一个钉子,那么也会绕着那个钉子以长度为0的绳子在转。

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

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

样例解释:

技术分享
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代码
技术分享
  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 }
qwq 一个补丁打了一晚上

 

以上是关于[51nod] 1467 旋转绳的主要内容,如果未能解决你的问题,请参考以下文章

51Nod 1347

51nod1347(简单逻辑)

51nod1347思维

51nod 1282 时钟

51nod 3174树状数组堆积木

处理屏幕旋转上的片段重复(带有示例代码)