P1852 [国家集训队]跳跳棋

Posted kafuuchino

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P1852 [国家集训队]跳跳棋相关的知识,希望对你有一定的参考价值。

P1852 [国家集训队]跳跳棋

lca

详细解析见题解

对于每组跳棋,我们可以用一个三元组(x,y,z)表示

我们发现,这个三元组的转移具有唯一性,收束性

也就是说,把每个三元组当成点,以转移关系为边,那么可以得到一棵树

显然最短步数==lca

然后我们就可以愉快地跑lca了

但是还要加优化,就是有可能出现2个靠得近的棋子,但与另一个棋子离得远的情况

这时要跳很多次,但是可以加速,详见代码

code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
using namespace std;
struct node{
    int a[3];
    bool operator == (const node &tmp) const{return a[0]==tmp.a[0]&&a[1]==tmp.a[1]&&a[2]==tmp.a[2];}
}f,t,p1,p2;
inline int find(node x){
    int d1=x.a[1]-x.a[0],d2=x.a[2]-x.a[1]; bool c=0;
    if(d1==d2) {p1=x; return 0;}
    if(d1<d2) swap(d1,d2),c=1;
    int cnt=d1/d2,d=d1%d2; //加速跳
    if(!d) d+=d2,--cnt;
    if(c) cnt+=find((node){x.a[2]-d-d2,x.a[2]-d,x.a[2]});
    else cnt+=find((node){x.a[0],x.a[0]+d,x.a[0]+d+d2});
    return cnt;
}
inline void change(node x,int step){
    int d1=x.a[1]-x.a[0],d2=x.a[2]-x.a[1]; bool c=0;
    if(d1==d2||!step) {p1=x; return ;}
    if(d1<d2) swap(d1,d2),c=1;
    int cnt=d1/d2,d=d1%d2;
    if(!d) d+=d2,--cnt;
    if(c){
        if(step>=cnt) change((node){x.a[2]-d-d2,x.a[2]-d,x.a[2]},step-cnt);
        else change((node){x.a[2]-d-d2*(cnt-step+1),x.a[2]-d-d2*(cnt-step),x.a[2]},0);
    }
    else{
        if(step>=cnt) change((node){x.a[0],x.a[0]+d,x.a[0]+d+d2},step-cnt);
        else change((node){x.a[0],x.a[0]+d+d2*(cnt-step),x.a[0]+d+d2*(cnt-step+1)},0);
    }
}
inline bool same(int k){
    change(f,k); node r1=p1;
    change(t,k); node r2=p1;
    return r1==r2;
}
int main(){
    scanf("%d%d%d%d%d%d",&f.a[0],&f.a[1],&f.a[2],&t.a[0],&t.a[1],&t.a[2]);
    sort(f.a,f.a+3); sort(t.a,t.a+3);
    int sp1=find(f); p2=p1;
    int sp2=find(t); //求相对于树根的深度
    if(!(p1==p2)) {printf("NO"); return 0;} //树根不同
    if(sp1<sp2) swap(sp1,sp2),swap(f,t);
    int ans=sp1-sp2;
    change(f,ans); f=p1; //使两点同一深度
    int l=0,r=sp2; //二分找lca
    while(l<r){
        int mid=l+((r-l)>>1);
        if(same(mid)) r=mid;
        else l=mid+1;
    }printf("YES
%d",(l<<1)+ans);
    return 0;
}

 

以上是关于P1852 [国家集训队]跳跳棋的主要内容,如果未能解决你的问题,请参考以下文章

P1852 [国家集训队]跳跳棋

P1852 跳跳棋 [LCA思想+二分答案]

P1852 跳跳棋(建模&LCA)

跳跳棋bzoj2144国家集训队

[luogu]P1852

跳跳棋