hdu 4262 Juggler(树状数组)

题意:某人手上有一串珠子,顺时针编号1--n,每次可进行三种操作:顺时针旋转一个珠子,逆时针旋转一个珠子,将手中的珠子移去(移去后顺时针方向下一个珠子进入手中),问按标号12345顺序将所有珠子逐一移去,最少需要多少次操作。

分析:假设当前要移除的珠子为x,x左边的珠子用A代表,右边的珠子用B代表即AxB,则无论左移还是右移都会得到xBA,即移去某个珠子对后面的珠子无影响,每次只需单独考虑A和B的长度,取最小累加即可。

做法:比赛时想复杂了,想维护每个珠子position的变化,一度想用伸展树旋转,没有充分利用循环性。自己找张小纸条转一下就很容易发现规律了(吾,有时过于感性了)

因为序列是循环的,因此每次旋转改变绝对位置不改变相对位置,因此记录当前手中珠子的初始位置cnt,若下个珠子的原始位置为pos,若cnt=pos则不需要转,若cnt<pos,设x为cnt与pos之间的珠子数,n为当前剩余的珠子,则旋转需要min(x,n-x)次cnt>pos时情况类似。用树状数组统计,每次一出后对应位置-1即可。

注意:下一次的位置不需要从当前位置开始顺时针找第一个存在的珠子,只需停在当前位置就好,因为当前位是0,不影响下一次树状数组的统计。 

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include<cmath>
using namespace std;
	int ss[100010],n;
	inline int lowbit(int k){
		return (k&-k);
	}
	void inc(int i,int k){
		while(i<=n){
			ss[i]+=k;
			i+=lowbit(i);
		}
	}
	int get(int i){
		int sum=0;
		while(i>0){
			sum+=ss[i];
			i-=lowbit(i);
		}
		return sum;
	}
	int pos[100010],p;
	int  main(){
		while(scanf("%d",&n)&&n!=0){
			for(int i=1;i<=n;i++){
				scanf("%d",&p);
				pos[p]=i;
				ss[i]=lowbit(i);
			}
			int cnt=1,x;
			long long ans=0;
			for(int i=1;i<=n;i++){
				ans++;
				if(cnt!=pos[i]){
					x=abs(get(cnt-1)-get(pos[i]-1));
					ans+=min(x,n-i+1-x);
				}
				cnt=pos[i];
				inc(pos[i],-1);
			}
			printf("%I64d\n",ans);
		}
	}


跑的很快,看来是正解!


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值