【BZOJ 2144】 2144: 跳跳棋 (倍增LCA)

2144: 跳跳棋

Time Limit: 10 Sec  Memory Limit: 259 MB
Submit: 642  Solved: 307

Description

跳跳棋是在一条数轴上进行的。棋子只能摆在整点上。每个点不能摆超过一个棋子。我们用跳跳棋来做一个简单的游戏:棋盘上有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 }
View Code

 

2017-04-05 09:13:21

 

posted @ 2017-04-05 09:13  konjak魔芋  阅读(453)  评论(0编辑  收藏  举报