6288. 2019.08.09【NOIP提高组A】旋转子段

63 篇文章 0 订阅

Description

Input

Output

Sample Input

Sample 1:
4
3 2 1 4

Sample 2:
2
1 2
 

Sample Output

Sample 1:
4

Sample 2:
2
 

Data Constraint

Hint

Solution

对于第i个位置上的数,它必须移动到第a[i]个位置上他才能是固定的数,我们发现可以将每个数旋转到自己位置上的操作的旋转中心求出来,将i挂在旋转中心上,然后将i到旋转中心的距离从小到大排个序,然后往左右扩展旋转中心上的所有点,答案可以O(1)求。因为旋转中心只有2n个,而最多有n个数被挂在旋转中心上,因此时间复杂度为O(n log n)。

Code 

#include<cstdio>
#include<algorithm>
#include<cstring>
#define I int
#define F(i,a,b) for(I i=a;i<=b;i++)
#define Fd(i,a,b) for(I i=a;i>=b;i--)
#define N 100010
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
#define open(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
using namespace std;
I rd(){
	I x=0,w=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*w;
}
I o,n,a[N],s[N],p,d[N],l[N*2],nx[N*2],t[N*2],ans;
void add(I x,I y){
	t[++t[0]]=y;nx[t[0]]=l[x];l[x]=t[0];
}
I cmp(I x,I y){return abs(x-o)<abs(y-o);}
I cmp2(I x,I y){
	I s1=x<=o?o-x:x-o-1,s2=y<=o?o-y:y-o-1;
	return s1<s2;
}
I main(){
	open("rotate");
	n=rd();
	F(i,1,n){
		a[i]=rd();
		if(a[i]>i){
			p=a[i]-i+1;
			if(p&1) add(i+p/2,i);
			else add(n+i-1+p/2,i);
		}
		else{
			p=i-a[i]+1;
			if(p&1) add(a[i]+p/2,i);
			else add(n+a[i]-1+p/2,i);
		}
		s[i]=s[i-1]+(a[i]==i);
	}
	F(i,1,n*2-1){
		d[0]=0;
		for(I k=l[i];k;k=nx[k]) d[++d[0]]=t[k];
		o=i;
		if(i<=n) sort(d+1,d+1+d[0],cmp);
		else{
			o-=n;
			sort(d+1,d+1+d[0],cmp2);	
		}
		F(j,1,d[0]){
			I x=d[j];
			if(x<a[x]) ans=max(ans,s[n]-s[a[x]]+s[x-1]+j);
			else ans=max(ans,s[n]-s[x]+s[a[x]-1]+j);
		}
	}
	printf("%d\n",ans);
	return 0;
}


作者:zsjzliziyang 
QQ:1634151125 
转载及修改请注明 
本文地址:https://blog.csdn.net/zsjzliziyang/article/details/98998415

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值