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 }