您的位置:首页 > 其它

【NOIP2016提高A组模拟8.15】Throw

2016-08-16 08:22 387 查看
本来这题是弃疗的,但是有人突然A了,我又燃起了希望



Input

六个数,开始位置和目标位置

Output

如果不行,NO,否则输出YES和步数

Sample Input

1 2 3

0 3 5

Sample Output

YES

2

Solution

三个人(x,y,z)的跳来跳去可以看做是一个二元组(l,r)在不停的变,l=y-x,r=z-y

当(x,y,z)跳时变成(x+l,y+l,z)…………等等,反应到二元组就是(l,r-l)(l-r,r),那么将状态(l,r)与前面两个状态连边,就变成了树形结构,将起始点与目标点的状态求距离就是答案。

二元组的变化很像辗转相除法,那就这么求深度,然后求LCA时用倍增思想,一次跳2k步,即(l,r)可能变成(l-k*r,r)

Code

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
int an;
int dep(int l,int r)
{
int k=0;for(int q=l/r,e=l%r;l!=r;l=r,r=e,q=l/r,e=l%r) if(e!=0) k+=q;else {k+=q-1;l=r;break;}
an=l;return k;
}
void jump(int &l,int &r,int k){
int q;
while(k>0)
{
if(l>r) q=min(l/r,k),l-=q*r;
else q=min(r/l,k),r-=q*l;k-=q;
}
}
int aj(int l,int r,int k){
while(k>0)
{
if(l==0||r==0)return 0;int q;
if(l>r) q=min(l/r,k),l-=q*r;
else q=min(r/l,k),r-=q*l;k-=q;
}
if(l==0||r==0) return 0;return l;
}
void px(int &a,int &b,int &c)
{
if(a>b)swap(a,b);if(b>c)swap(b,c);if(a>b)swap(a,b);
}
int main()
{
int x,y,z,x1,y1,z1;
scanf("%d%d%d%d%d%d",&x,&y,&z,&x1,&y1,&z1);
px(x,y,z);px(x1,y1,z1);
int l=y-x,r=z-y,l1=y1-x1,r1=z1-y1;
int k=dep(l,r);int an1=an;int k1=dep(l1,r1);
if(an1!=an) {printf("NO");return 0;}int ans=0;
fd(i,log2(k),0) if(k-(1<<i)>=k1) ans+=1<<i,jump(l,r,(1<<i)),k-=(1<<i);
fd(i,log2(k1),0) if(k1-(1<<i)>=k) ans+=1<<i,jump(l1,r1,(1<<i)),k1-=(1<<i);
fd(i,min(log2(k),log2(k1)),0)
if(aj(l,r,1<<i)!=aj(l1,r1,1<<i)) ans+=(1<<i)*2,jump(l,r,(1<<i)),jump(l1,r1,(1<<i));
if(l!=l1) ans+=2;
printf("YES\n%d",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: