HDU3830 Checkers【LCA】

题意:三个数字,每个数字可以以一个数字为中心,翻转到另一边(只能翻过一个数字),给你两个三元组,问一个变成另一个最少需要几步


思路:三个数字,中间的往两边翻的话,边上两个数字,相互交替,无穷无尽。如果,边上的往中间翻的话,总会结束。结束的时候就是它的根。那我们,找到它们的根,根相同,去找它们的步数,可能没走到根,它们就一样了。先让它们走到同一深度,再二分,mid步都相同,r = mid;否则,l = mid+1。这些还不是关键,关键的是翻的速度,比如三个数1、2、101,我们不能一步步翻(2、3、101; 3、4、101……),这样太慢了,能不能直接翻到99、100、101。假若左边间隔d1 > 右边间隔d2,步数s = (d1-1) / d2; a1 -= s * d2,a2 -=s * d2 (三个数为a0,a1,a2,已排序);d1 < d2同理。


#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<stdlib.h>
#include<math.h>
#include<vector>
#include<list>
#include<map>
#include<stack>
#include<queue>
#include<algorithm>
#include<numeric>
#include<functional>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxn = 3;
int a[maxn],b[maxn],c[maxn],d[maxn];
int fa[maxn][maxn];

int fid(int x)
{
	if(x == 1)
		memcpy(a,c,3*sizeof(int));
	else
		memcpy(a,d,3*sizeof(int));
	int t = 0,dis;
	sort(a,a+3);
	int d1,d2;
	d1 = a[1] - a[0];
	d2 = a[2] - a[1];
	while( d1 != d2)
	{
		if(d1 < d2)
		{
			dis = (d2-1) / d1;
			a[1] += dis*d1;
			a[0] += dis*d1;
			t += dis; 
		}
		else
		{
			dis = (d1-1) / d2;
			a[2] -= dis * d2;
			a[1] -= dis * d2;
			t += dis;
		}	
		sort(a,a+3);
		d1 = a[1] - a[0];
		d2 = a[2] - a[1];
	}
	fa[x][0] = a[0];
	fa[x][1] = a[1];
	fa[x][2] = a[2];
	return t;
}

void go(int a[],int t)
{
	int dis;
	sort(a,a+3);
	int d1,d2;
	d1 = a[1] - a[0];
	d2 = a[2] - a[1];
	while(t)
	{
		if(d1 < d2)
		{
			dis = (d2-1) / d1;
			if(dis > t)
				dis = t;
			a[1] += dis*d1;
			a[0] += dis*d1;
			t -= dis; 
		}
		else
		{
			dis = (d1-1) / d2;
			if(dis > t)
				dis = t;
			a[2] -= dis * d2;
			a[1] -= dis * d2;
			t -= dis;		
		}		
		sort(a,a+3);
		d1 = a[1] - a[0];
		d2 = a[2] - a[1];
	}
}

int check(int t)
{
	int dis;
	memcpy(a,c,3*sizeof(int));
	memcpy(b,d,3*sizeof(int));
	int tt = t;
	sort(a,a+3);
	int d1,d2;
	d1 = a[1] - a[0];
	d2 = a[2] - a[1];
	while(t)
	{
		if(d1 < d2)
		{
			dis = (d2-1) / d1;
			if(dis > t)
				dis = t;
			a[1] += dis*d1;
			a[0] += dis*d1;
			t -= dis; 
		}
		else
		{
			dis = (d1-1) / d2;
			if(dis > t)
				dis = t;
			a[2] -= dis * d2;
			a[1] -= dis * d2;
			t -= dis;		
		}			
		sort(a,a+3);
		d1 = a[1] - a[0];
		d2 = a[2] - a[1];
	}	
	sort(b,b+3);
	d1 = b[1] - b[0];
	d2 = b[2] - b[1];
	while(tt)
	{
		if(d1 < d2)
		{
			dis = (d2-1) / d1;
			if(dis > tt)
				dis = tt;
			b[1] += dis*d1;
			b[0] += dis*d1;
			tt -= dis; 
		}
		else
		{
			dis = (d1-1) / d2;
			if(dis > tt)
				dis = tt;
			b[2] -= dis * d2;
			b[1] -= dis * d2;
			tt -= dis;		
		}	
		sort(b,b+3);
		d1 = b[1] - b[0];
		d2 = b[2] - b[1];
	}	
	if(a[0] == b[0] && a[1] == b[1]  && a[2] == b[2] )
		return 1;
	else
		return 0;
}

void bir(int l,int r,int have)
{
	while(l < r)
	{
		int mid = (l+r) / 2;
		if(check(mid))
			r = mid;
		else
			l = mid+1;
	}
	printf("%d\n",2*l+have);
}

int main(void)
{
	while(scanf("%d%d%d",&c[0],&c[1],&c[2])!=EOF)
	{
		scanf("%d%d%d",&d[0],&d[1],&d[2]);
		int num1 = fid(1);
		int num2 = fid(2);
		if(fa[1][0] == fa[2][0] && fa[1][1] == fa[2][1] && fa[1][2] == fa[2][2])
		{
			printf("YES\n");
			if(num1 < num2)
			{
				go(d,num2-num1);
				bir(0,min(num1,num2),num2-num1);
			}
			else
			{
				go(c,num1-num2);
				bir(0,min(num1,num2),num1-num2);
			}
		}
		else
			printf("NO\n");	
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值