bzoj 2144 跳跳棋

题目大意:

棋盘上有3颗棋子,分别在a,b,c这三个位置。我们要通过最少的跳动把他们的位置移动成x,y,z 棋子是没有区别的

跳动的规则很简单,任意选一颗棋子,对一颗中轴棋子跳动 跳动后两颗棋子距离不变 一次只允许跳过1颗棋子

思路:

每个状态可以向三个状态转移 中间的向两边和两边中靠近中间的那一个向中间跳

因此状态就可以构成一颗树 我们可以查找两个状态在树上的lca

查找lca可以加速 处理出所有祖先

先把两个状态放到同一深度

然后二分 判断

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstdlib>
 5 #include<cstring>
 6 #include<algorithm>
 7 #include<vector>
 8 #include<queue>
 9 #define inf 2139062143
10 #define ll long long
11 #define MAXN 2001000
12 using namespace std;
13 inline int read()
14 {
15     int x=0,f=1;char ch=getchar();
16     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
17     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
18     return x*f;
19 }
20 int l1,l2,res;
21 struct node
22 {
23     int x,y,z;
24     bool operator == (const node &t) const
25     {
26         return x==t.x&&y==t.y&&z==t.z;
27     }
28     bool operator != (const node &t) const
29     {
30         return x!=t.x||y!=t.y||z!=t.z;
31     }
32 }a,b,f1,f2;
33 node work(node t,int x)
34 {
35     for(int tmp=res=0,l,r;x;res+=tmp)
36     {
37         l=t.y-t.x,r=t.z-t.y;
38         if(l==r) return t;
39         if(l<r) tmp=min(x,(r-1)/l),t.x+=tmp*l,t.y+=tmp*l,x-=tmp;
40         else tmp=min(x,(l-1)/r),t.y-=tmp*r,t.z-=tmp*r,x-=tmp;
41     }
42     return t;
43 }
44 int main()
45 {
46     a.x=read(),a.y=read(),a.z=read(),b.x=read(),b.y=read(),b.z=read();
47     if(a.x>a.y) swap(a.x,a.y);if(a.y>a.z) swap(a.y,a.z);if(a.x>a.y) swap(a.x,a.y);
48     if(b.x>b.y) swap(b.x,b.y);if(b.y>b.z) swap(b.y,b.z);if(b.x>b.y) swap(b.x,b.y);
49     f1=work(a,inf),l1=res,f2=work(b,inf),l2=res;
50     if(f1!=f2) {puts("NO");return 0;}
51     if(l1<l2) {swap(a,b);swap(l1,l2);}
52     a=work(a,l1-l2);int l=0,r=l2,mid,ans;
53     while(r>=l)
54     {
55         mid=(l+r)>>1;
56         if(work(a,mid)==work(b,mid)) ans=mid,r=mid-1;
57         else l=mid+1;
58     }
59     printf("YES\n%d",l1-l2+(ans<<1));
60 }
View Code

 

posted @ 2018-09-04 19:38  jack_yyc  阅读(163)  评论(0编辑  收藏  举报