【BZOJ 2144】 2144: 跳跳棋 (倍增LCA)
2144: 跳跳棋
Time Limit: 10 Sec Memory Limit: 259 MB
Submit: 642 Solved: 307Description
跳跳棋是在一条数轴上进行的。棋子只能摆在整点上。每个点不能摆超过一个棋子。我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置。我们要通过最少的跳动把他们的位置移动成x,y,z。(棋子是没有区别的)跳动的规则很简单,任意选一颗棋子,对一颗中轴棋子跳动。跳动后两颗棋子距离不变。一次只允许跳过1颗棋子。 写一个程序,首先判断是否可以完成任务。如果可以,输出最少需要的跳动次数。
Input
第一行包含三个整数,表示当前棋子的位置a b c。(互不相同)第二行包含三个整数,表示目标位置x y z。(互不相同)
Output
如果无解,输出一行NO。如果可以到达,第一行输出YES,第二行输出最少步数。
Sample Input
1 2 3
0 3 5
Sample Output
YES
2
【范围】
100% 绝对值不超过10^9
HINT
Source
【分析】
神奇的题目。!!
ORZ hzwer
这样考虑只用考虑往中间跳了,这样的话你当然不会傻傻地一步步跳,跟辗转相除差不多的,可以快速求出连续跳x步到的地方。
于是你用倍增求LCA就能知道两点间路径的长度了。
【我觉得厉害的地方就是转成树形,看出来是只用两边考虑往中间跳的。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 #define INF 0x7fffffff 8 9 int a[5][5]; 10 int mymin(int x,int y) {return x<y?x:y;} 11 12 int ffind(int x,int y) 13 { 14 int t1=a[x][2]-a[x][1],t2=a[x][3]-a[x][2]; 15 if(t1==t2) return 0; 16 int xx; 17 if(t1<t2) 18 { 19 xx=mymin(y,(t2-1)/t1); 20 y-=xx; 21 a[x][1]+=xx*t1;a[x][2]+=xx*t1; 22 } 23 else 24 { 25 xx=mymin(y,(t1-1)/t2); 26 y-=xx; 27 a[x][2]-=xx*t2;a[x][3]-=xx*t2; 28 } 29 if(y) return ffind(x,y)+xx; 30 else return xx; 31 } 32 33 int main() 34 { 35 for(int i=1;i<=3;i++) scanf("%d",&a[0][i]); 36 for(int i=1;i<=3;i++) scanf("%d",&a[1][i]); 37 sort(a[0]+1,a[0]+1+3); 38 sort(a[1]+1,a[1]+1+3); 39 int d1,d2; 40 for(int i=1;i<=3;i++) a[3][i]=a[0][i]; d1=ffind(3,INF); 41 for(int i=1;i<=3;i++) a[4][i]=a[1][i]; d2=ffind(4,INF); 42 if(a[3][1]!=a[4][1]||a[3][2]!=a[4][2]||a[3][3]!=a[4][3]) printf("NO\n"); 43 else 44 { 45 if(d1<d2) 46 { 47 swap(d1,d2); 48 for(int i=1;i<=3;i++) swap(a[0][i],a[1][i]); 49 } 50 int ans=ffind(0,d1-d2); 51 int l=0,r=INF; 52 while(l<r) 53 { 54 int mid=(l+r)>>1; 55 for(int i=1;i<=3;i++) a[3][i]=a[0][i]; d1=ffind(3,mid); 56 for(int i=1;i<=3;i++) a[4][i]=a[1][i]; d2=ffind(4,mid); 57 if(a[3][1]!=a[4][1]||a[3][2]!=a[4][2]||a[3][3]!=a[4][3]) 58 { 59 l=mid+1; 60 // for(int i=1;i<=3;i++) a[0][i]=a[3][i]; 61 // for(int i=1;i<=3;i++) a[1][i]=a[4][i]; 62 } 63 else r=mid; 64 } 65 printf("YES\n%d\n",ans+2*l); 66 } 67 return 0; 68 }
2017-04-05 09:13:21