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
",idx[Get_ans(p[now],len,1)]);
	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/joyouth/p/5368873.html