版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/82284356
解析:
隐藏了的思维好题。
由于棋子之间没有区别,所以可以干一些妙妙的事情。
考虑选择一颗棋子a以b为对称点跳跃,跳完之后a和b的距离是不变的!!!
这就是本题的第一个关键,我们设三个棋子从左到右为a,b,c。a,b,c也表示其坐标。
我们显然知道如果一直是中间两个棋子向着两边跳跃,是没有尽头的,但是如果向中间跳,一定会有一个时刻,三个棋子无法再向中间跳,此时 ,我们称其为初始状态。这是本题的第二个关键。
由初始状态开始,我们只考虑中间棋子向两边跳,每次两种选择,并且我们不考虑两边棋子向中间跳(因为一定会回到上一个状态)。所以,由同一初始状态能够转移到的状态的集合是一定的。这是本题的第三个关键。
就像一棵二叉树,离根最近的某深度的后代总是有若干个,而离一个节点某固定深度的祖先节点只有一个。
现在是重头戏。
如果 输入状态的初始状态 和输出状态的初始状态 相同,(即它们的状态在同一棵树里面)那他们一定可以相互到达,反之一定不能。
没学过倍增求LCA的小伙伴看这里。
先将起始和末状态的深度较深的一个向上跳,跳到同一深度,然后就像倍增一样求一下他们的LCA。
具体求法可以用倍增也可以用二分答案。
Tips:最后一点要注意的地方:
如何跳?当a,b很近而b,c很远的时候,老老实实地跳实在是很浪费时间。
那么跳到什么时候a,b就跳不动了,再考虑换b,c跳呢?
就是跳到
的时候,直接除法取得跳多少步,取模取得最终距离就好了
扫描二维码关注公众号,回复:
3017321 查看本文章
代码:
#include<bits/stdc++.h>
using namespace std;
#define re register
#define gc getchar
#define pc putchar
#define cs const
#define st static
inline
int getint(){
re int num=0;
re char c=gc();
re bool f=1;
for(;!isdigit(c);c=gc())if(c=='-')f=0;
for(;isdigit(c);c=gc())num=(num<<1)+(num<<3)+(c^48);
return f?num:-num;
}
struct node{
int a,b,c;
pair<node,int> getend(){
node tmp=*this;
int ans=0;
while(b-a!=c-b){
if(b-a>c-b){
int dis=c-b;
ans+=(b-a)/dis;
b=a+(b-a)%dis;
if(b==a)b=a+dis,--ans;
c=b+dis;
}
if(b-a<c-b){
int dis=b-a;
ans+=(c-b)/dis;
b=c-(c-b)%dis;
if(b==c)b=c-dis,--ans;
a=b-dis;
}
}
node Ans=*this;
*this=tmp;
return make_pair(Ans,ans);
}
node jump(int step){
node tmp=*this;
while(step){
if(b-a>c-b){
int dis=c-b;
if((b-a)/dis<=step){
step-=(b-a)/dis;
b=a+(b-a)%dis;
if(b==a)b=a+dis,++step;
c=b+dis;
}
else{
b-=step*dis;
c-=step*dis;
step=0;
}
}
if(b-a<c-b){
int dis=b-a;
if((c-b)/dis<=step){
step-=(c-b)/dis;
b=c-(c-b)%dis;
if(b==c)b=c-dis,++step;
a=b-dis;
}
else {
b+=step*dis;
a+=step*dis;
step=0;
}
}
}
node Ans=*this;
*this=tmp;
return Ans;
}
node get(){
int tmp[3];
tmp[0]=getint();
tmp[1]=getint();
tmp[2]=getint();
sort(tmp,tmp+3);
a=tmp[0];
b=tmp[1];
c=tmp[2];
}
friend bool operator==(cs node &s,cs node &t){
return s.a==t.a&&s.b==t.b&&s.c==t.c;
}
friend bool operator!=(cs node &s,cs node &t){
return !(s==t);
}
};
node start,expect;
int ans;
int l,r;
int main(){
start.get();
expect.get();
pair<node,int> se=start.getend();
pair<node,int> te=expect.getend();
if(se.first!=te.first){
puts("NO");
return 0;
}
if(se.second>te.second){
start=start.jump(se.second-te.second);
ans+=se.second-te.second;
r=te.second;
}
else if(se.second<=te.second){
expect=expect.jump(te.second-se.second);
ans+=te.second-se.second;
r=se.second;
}
while(l<r){
int mid=(l+r)>>1;
if(start.jump(mid)==expect.jump(mid))r=mid;
else l=mid+1;
}
puts("YES");
cout<<(long long)ans+l*2;
return 0;
}