[CodeForces-555D]Case of a Top Secret
题目大意:
一个直线上有n个钉子,现在分别在某个钉子上挂一段系有重物的绳子,对这个物体是加一个向右的力,使它作圆周运动,
绳子最终一定会缠在一些钉子上并围绕某一个钉子做圆周运动。
问最终会围哪个钉子做运动。
思路:
考虑暴力模拟,每次二分查找绳子会转到哪里,并对绳子减去区间的长度,这样能拿到10分。
显然绳子有些时候会在同样一段区间上转很多次,因此我们可以取模避免重复减,这样能拿到30分。
观察发现每次绳子能够旋转的范围是在不断缩减的,而且左端点越来越大,右端点越来越小,这样我们可以每次缩减一下二分的范围,这样就能拿到100分。
注意第一次旋转时不能直接取模。
1 #include<cstdio> 2 #include<cctype> 3 #include<vector> 4 #include<algorithm> 5 inline int getint() { 6 register char ch; 7 register bool neg=false; 8 while(!isdigit(ch=getchar())) if(ch=='-') neg=true; 9 register int x=ch^'0'; 10 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 11 return neg?-x:x; 12 } 13 const int N=200001; 14 struct Point { 15 int x,id; 16 bool operator < (const int &another) const { 17 return x<another; 18 } 19 bool operator < (const Point &another) const { 20 return x<another.x; 21 } 22 }; 23 std::vector<Point> v; 24 int x[N]; 25 int main() { 26 const int n=getint(); 27 int m=getint(); 28 for(register int i=1;i<=n;i++) { 29 v.push_back((Point){x[i]=getint(),i}); 30 } 31 std::sort(v.begin(),v.end()); 32 while(m--) { 33 std::vector<Point>::iterator b=v.begin(),e=v.end(); 34 int last=0,i=getint(),l=getint(); 35 bool d=true; 36 last=i; 37 e=std::lower_bound(b,e,x[i]+l+1); 38 i=(e-1)->id; 39 l-=x[i]-x[last]; 40 if(last==i) { 41 b=std::lower_bound(b,e,x[i]-l); 42 i=b->id; 43 l-=x[last]-x[i]; 44 } 45 while(last!=i) { 46 if(d) { 47 last=i; 48 e=std::lower_bound(b,e,x[i]+l+1); 49 i=(e-1)->id; 50 if(i==last) { 51 d^=true; 52 goto Left; 53 } 54 if((l/(x[i]-x[last]))&1) { 55 d^=true; 56 } else { 57 std::swap(last,i); 58 } 59 l%=x[i]-x[last]; 60 } 61 Left: 62 if(!d) { 63 last=i; 64 b=std::lower_bound(b,e,x[i]-l); 65 i=b->id; 66 d^=true; 67 l-=x[last]-x[i]; 68 } 69 } 70 printf("%d\n",i); 71 } 72 return 0; 73 }