codeforces #310 div1 D
一开始写了个暴力模拟绳子的摆动轨迹
然后在Test 16 T掉了
后来%了一下别人的代码,发现需要对特殊情况进行特殊处理
首先我们考虑绳子的向右摆动,设当前位置为p,绳子当前长度为L
如果其旋转中心位置>p+L/2,那么绳子长度至少会缩短一半
假设一直这样下去,时间复杂度为log(L)
但是当旋转中心位置<p+L/2的时候就比较复杂了,我们发现暴力模拟很容易被卡成单次O(L)
因为这个时候会出现绳子不断地在两个点之间转来转去,每次减少绳长很少
但是我们又会发现挡在两个点之间旋转时候,转一圈减少的长度为2*(p1-p2)
那么不断的在两个点之间旋转我们只需要令L=L%(2*(p1-p2)) 即可
这样就不会被卡成O(L)了
至于对最后答案的判定,我们只需要旋转两次,如果这两次旋转中心相同,证明这就是答案
#include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> using namespace std; const int maxn=200010; int n,m,now,len; int a[maxn]; int idx[maxn]; int p[maxn]; bool cmp(const int &u,const int &v){return a[u]<a[v];} int Rotate(int id,int L,int f){ if(f==1)return upper_bound(a+1,a+n+1,a[id]+L)-a-1; else return lower_bound(a+1,a+n+1,a[id]-L)-a; } int Get_ans(int id,int L,int f){ int n1=Rotate(id,L,f); int n2=Rotate(n1,L-abs(a[n1]-a[id]),f^1); if(n2==id){ if(id==n1)return id; int d=2*abs(a[id]-a[n1]); return Get_ans(id,L%d,f); }else Get_ans(n1,L-abs(a[n1]-a[id]),f^1); } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;++i)scanf("%d",&a[i]),idx[i]=i; sort(idx+1,idx+n+1,cmp);sort(a+1,a+n+1); for(int i=1;i<=n;++i)p[idx[i]]=i; while(m--){ scanf("%d%d",&now,&len); printf("%d\n",idx[Get_ans(p[now],len,1)]); } return 0; }