HDU 3830 Checkers(二分+lca)

Description

Little X, Little Y and Little Z are playing checkers when Little Y is annoyed. So he wants to make the chessboard much bigger. Although Little Z insists the original version, Little X stands by Little Y. After they enlarge the chessboard, the chessboard turns to an infinite line.

The chessboard is like the Number Axes now, with each integer point able to hold a checker. At initial status there are three checkers on three different integer points , and through the game there always are three checkers. Every time, they can choose a checker A to jump across a pivot checker B to a new position(but the distance between old A and B equals to new A and B, and there should be no other checkers except B in the range [old A, new A]).

After playing for a while, they wonder whether an given status a,b,c can be transferred to x,y,z. obeying the rules. Since the checkers are considered the same, it is unnecessary for a must jump to x.

Input Format

The first line is a,b,c. The second line is x,y,z. They are all integers in range (-10^9, 10^9) and the two status are valid.

Output Format

The first line is YES or NO, showing whether the transfer can be achieved. If it is YES, then output the least steps in the second line.

Sample Input

1 2 3
0 3 5

Sample Output

YES
2

一题思维好题

自己在草稿纸上手模一下;

设 a<b<c

则下一步为 2a-b a c或a c 2c-b;

若 b-a<c-b; 上一步为  b 2b-a c

若 b-a>c-b; 上一步为  a 2b-c b;

可以发现 中间点往外扩 a b c 距离增加;

反之减小;

将图画出 图是一颗二叉树!!!!;

下一步就是扩展儿子;上一步访问父亲;

那么再思考根节点问题 ;

对每个状态 它不停往上走 a b c 距离会减小;

直到 b-a=c-b;那快速找根节点只要用辗转相除就好;

那么 题目询问的第一个问题就好解决了;只要找根节点就行了;

第二个问题 ;

由于此题建图+lca麻烦而且数据也较大 空间不允许 ;那我们可以采用二分+lca

先把起始和终止状态调整到同一高度;

然后二分上升高度 往上走 判断是否相同就行了;(也要用辗转相除)

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
struct state{int x,y,z,d;};
state st,ed;
int n,i,j,l,k,m,r;
void sor(state &now)
{
	if(now.x>now.y)swap(now.x,now.y);
	if(now.y>now.z)swap(now.y,now.z);
	if(now.x>now.y)swap(now.x,now.y);
}
state root(state &now)
{
	int q=-1,p=1,r;
	state pre=now;
	while(q!=p)
	{
		q=pre.y-pre.x;p=pre.z-pre.y;
		if(p<q)
		{
			r=(q-1)/p;
			pre.y-=r*p;
			pre.z-=r*p;
		}
		else
		{
			r=(p-1)/q;
			pre.x+=r*q;
			pre.y+=r*q;
		}
		now.d+=r;
		sor(pre);
	}
	pre.d=0;
	return pre;
}
bool equr(state a,state b)
{return a.x==b.x&&a.y==b.y&&a.z==b.z ? true : false;};
state up(state now,int num)
{
 	int p=-1,q=1,r;
	while(num&&q!=p)
	{
		p=now.y-now.x;q=now.z-now.y;
		if(q<p)
		{
			r=min(num,(p-1)/q);
			now.y-=q*r;
			now.z-=q*r;
		}
		else
		{
			r=min(num,(q-1)/p);
			now.x+=p*r;
			now.y+=p*r;
		}
		num-=r;
		sor(now);
	}
	return now;	
}
bool check(int mid)
{
	state nex1=st,nex2=ed;
	nex1=up(nex1,mid+st.d-ed.d);nex2=up(nex2,mid);
	if(equr(nex1,nex2))return true;
	return false;
} 
int main()
{
//	freopen("xx.in","r",stdin);
	while(scanf("%d%d%d%d%d%d",&st.x,&st.y,&st.z,&ed.x,&ed.y,&ed.z)==6)
	{
		sor(st);sor(ed);st.d=ed.d=0;
		if(!equr(root(st),root(ed)))
		printf("NO\n");
		else
		{
			int mid,ans;
			l=0;r=max(st.d,ed.d);
			if(st.d<ed.d)swap(st,ed);
			while(l<=r)
			{
				mid=(l+r)>>1;
				if(check(mid))r=mid-1,ans=mid;
				else l=mid+1;
			}
			printf("YES\n%d\n",st.d-ed.d+ans*2);
		}
	}
}

  

 

posted @ 2016-10-31 11:56  peter863  阅读(235)  评论(0编辑  收藏  举报