跳跳棋bzoj2144国家集训队

题目描述

跳跳棋是在一条数轴上进行的。棋子只能摆在整点上。每个点不能摆超过一个棋子。

我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置。我们要通过最少的跳动把他们的位置移动成x,y,z。(棋子是没有区别的)

跳动的规则很简单,任意选一颗棋子,对一颗中轴棋子跳动。跳动后两颗棋子距离不变。一次只允许跳过1颗棋子。

写一个程序,首先判断是否可以完成任务。如果可以,输出最少需要的跳动次数。

输入输出格式

输入格式:

第一行包含三个整数,表示当前棋子的位置a b c。(互不相同)

第二行包含三个整数,表示目标位置x y z。(互不相同)

输出格式:

如果无解,输出一行NO。

如果可以到达,第一行输出YES,第二行输出最少步数。

输入输出样例

输入样例#1: 复制

1 2 3
0 3 5

输出样例#1: 复制

YES
2

说明

20% 输入整数的绝对值均不超过10

40% 输入整数的绝对值均不超过10000

100% 绝对值不超过10^9

分析

这个题目是真的蛇皮,没话讲。

本题是一道LCA加二分的题目,以我的智商是看不出来的。

下面就来说一下我在SAC大佬的帮助下怎么分析的吧。

设最左边的棋子为a,中间棋子为b,最右边的棋子为c。

显而易见只有三种跳跃方式。

1.b往左边跳。

2.b往右边跳。

3.离b近的往里跳(离b远的不可以跳,因为会越过两个棋子)。

当a,c距离和b一样时,就把当前状态设为a,b,c的起始状态,而且a,b,c的起始状态只有一种。

所以判断一下a,b,c起始状态和不和x,y,z的起始状态一不一样就行了。

怎么判断呢?

显然,两个棋子往中间跳才可以回到起始状态。

但是,如果纯模拟的话就又会超时。

比如1,2,100000000。

这样就会进行很多次操作。

此时,设d1=b-a,d2=c-b。

d1小于d2时我们移动a,然后会发现d1没变,d2减小了d1所以我们可以连续走d2/d1次,反之亦然,此时d2小于d1了换个方向走。注意:d2%d1等于0时走d2/d1-1步就到根了。

然后怎么判断要走多少步呢?

枚举显然不行。

那就二分吧。

如果当前二分得到的mid可以使他们状态相同。

缩小上界,否则扩大下界,下面就贴上代码了(自认为写的很清楚)

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
void sot(ll &a,ll &b,ll &c)
{
    if(a>b)
    swap(a,b);
    if(a>c)
    swap(a,c);
    if(b>c)
    swap(b,c);
}
ll min(ll x,ll y)
{
    if(x>y)
    return y;
    return x;
}
ll getfa(ll a,ll b,ll c,ll &dep,ll &d)
{
    ll d1=b-a,d2=c-b;
    while(d1!=d2)
    {
        if(d1<d2)
        {
            ll sum=d2/d1,t=d2%d1;
            if(t==0)
            {
                dep+=(sum-1);
                d=d1;
                return a+(sum-1)*d1;
            }
            else
            {
                dep+=sum;
                d2=t;
                a+=(sum)*d1;
                b+=(sum)*d1;

            }
        }
        else
        {
            ll sum=d1/d2,t=d1%d2;
            if(t==0)
            {
                dep+=(sum-1);
                d=d2;
                return a;
            }
            else
            {
                dep+=sum;
                d1=t;
                b-=(sum)*d2;
                c-=(sum)*d2;
            }
        }
    }
    dep=0;
    d=d1;
    return a;
}
void fa(ll &a,ll &b,ll &c,ll step)
{
    ll d1=b-a,d2=c-b;
    while(step>0)
    {
        if(d1<d2)
        {
            ll sum=d2/d1,t=d2%d1;
            if(sum>=step)
            {
                a+=step*d1;
                b+=step*d1;
                if(b==c) b=a,a-=d1;
                return;
            }
            else
            {
                step-=sum;
                b=c-t;
                a=b-d1;
                d2=t;
            }
        }
        else
        {
            ll sum=d1/d2,t=d1%d2;
            if(sum>=step)
            {
                b-=step*d2;
                c-=step*d2;
                if(a==b) b=c,c+=d2;
                return;
            }
            else
            {
                step-=sum;
                b=a+t;
                c=b+d2;
                d1=t;
            }
        }
    }
}
int main()
{
    ll a,b,c,x,y,z,dep1=0,dep2=0,len=0,k=0,kk=0;
    cin>>a>>b>>c>>x>>y>>z;
    sot(a,b,c);
    sot(x,y,z);
    ll kzj=getfa(a,b,c,dep1,k);
    ll pwq=getfa(x,y,z,dep2,kk);
    if(k!=kk||kzj!=pwq) {cout<<"NO";return 0;}
    else
    {
        if(dep1<dep2)
        {
            len+=dep2-dep1;
            fa(x,y,z,len);
        }
        else
        {
            len+=dep1-dep2;
            fa(a,b,c,len);
        }
    }
    ll l=0,r=min(dep1,dep2),ans=0;
    while(l<=r)
    {
        ll mid=(l+r)/2;
        ll a1=a,b1=b,c1=c,x1=x,y1=y,z1=z;
        fa(a1,b1,c1,mid);
        fa(x1,y1,z1,mid);
        if(a1==x1&&b1==y1&&c1==z1)
        r=mid-1,ans=mid;
        else
        l=mid+1;
    }
    cout<<"YES"<<endl;
    cout<<ans*2+len;
}

原文地址:https://www.cnblogs.com/kzj-pwq/p/8609977.html

时间: 2024-08-10 11:57:21

跳跳棋bzoj2144国家集训队的相关文章

P1852 [国家集训队]跳跳棋

P1852 [国家集训队]跳跳棋 lca 详细解析见题解 对于每组跳棋,我们可以用一个三元组(x,y,z)表示 我们发现,这个三元组的转移具有唯一性,收束性 也就是说,把每个三元组当成点,以转移关系为边,那么可以得到一棵树 显然最短步数==lca 然后我们就可以愉快地跑lca了 但是还要加优化,就是有可能出现2个靠得近的棋子,但与另一个棋子离得远的情况 这时要跳很多次,但是可以加速,详见代码 code: #include<iostream> #include<cstdio> #in

bzoj2144 跳跳棋

Description 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他们的位置移动成x,y,z.(棋子是没有区别的)跳动的规则很简单,任意选一颗棋子,对一颗中轴棋子跳动.跳动后两颗棋子距离不变.一次只允许跳过1颗棋子.  写一个程序,首先判断是否可以完成任务.如果可以,输出最少需要的跳动次数. Input 第一行包含三个整数,表示当前棋子的位置a b c.(互不相同)

bzoj2144 跳跳棋 二分

[bzoj2144]跳跳棋 Description 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他们的位置移动成x,y,z.(棋子是没有区别的)跳动的规则很简单,任意选一颗棋子,对一颗中轴棋子跳动.跳动后两颗棋子距离不变.一次只允许跳过1颗棋子.  写一个程序,首先判断是否可以完成任务.如果可以,输出最少需要的跳动次数. Input 第一行包含三个整数,表示当前棋子的

【资料】国家集训队论文集(1999~2014)

本文版权归ACShiryu和acvay所有,如转载请注明原作者. 国家集训队1999论文集 1.陈宏:<数据结构的选择与算法效率--从IOI98试题PICTURE谈起> 2.来煜坤:<把握本质,灵活运用--动态规划的深入探讨> 3.齐鑫:<搜索方法中的剪枝优化> 4.邵铮:<数学模型的建立.比较和应用> 5.石润婷:<隐蔽化.多维化.开放化--论当今信息学竞赛中数学建模的灵活性> 6.杨帆:<准确性.全面性.美观性--测试数据设计中的三要素

2038: [2009国家集训队]小Z的袜子(hose)+莫队入门

题目链接:2038: [2009国家集训队]小Z的袜子(hose) 题目: Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命……具体来说,小Z把这N只袜子从1到N编号,然后从编号L到R(L 尽管小Z并不在意两只袜子是不是完整的一双,甚至不在意两只袜子是否一左一右,他却很在意袜子的颜色,毕竟穿两只不同色的袜子会很尴尬.你的任务便是告诉小Z,他有多大的概率抽到两只颜色相同的袜子

跳跳棋(9018_1563)(BZOJ_2144)

题目: Hzwer的跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子. 某一天,黄金大神和cjy用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.他们要通过最少的跳动把它们的位置移动成x,y,z.(棋子是没有区别的) 跳动的规则很简单,任意选一颗棋子,对一颗中轴棋子跳动.跳动后两颗棋子距离不变.一次只允许跳过1颗棋子. 写一个程序,首先判断是否可以完成任务.如果可以,输出最少需要的跳动次数. 这道题的状态是可以在树上处理的,对于一个中间到两端距离不

国家集训队2011 happiness

[试题来源] 2011中国国家集训队命题答辩 [问题描述] 高一一班的座位表是个n*m的矩阵,经过一个学期的相处,每个同学和前后左右相邻的同学互相成为了好朋友.这学期要分文理科了,每个同学对于选择文科与理科有着自己的喜悦值,而一对好朋友如果能同时选文科或者理科,那么他们又将收获一些喜悦值.作为计算机竞赛教练的scp大老板,想知道如何分配可以使得全班的喜悦值总和最大. [输入格式] 第一行两个正整数n,m.接下来是六个矩阵第一个矩阵为n行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学

[国家集训队2010]小Z的袜子

★★★   输入文件:hose.in   输出文件:hose.out   简单对比 时间限制:1 s   内存限制:512 MB [题目描述] 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命…… 具体来说,小Z把这N只袜子从1到N编号,然后从编号L到R(L 尽管小Z并不在意两只袜子是不是完整的一双,甚至不在意两只袜子是否一左一右,他却很在意袜子的颜色,毕竟穿两只不同色的袜子会很尴尬. 你的任务便

BZOJ 2144 跳跳棋

2144: 跳跳棋 Description 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他们的位置移动成x,y,z.(棋子是没有区别的)跳动的规则很简单,任意选一颗棋子,对一颗中轴棋子跳动.跳动后两颗棋子距离不变.一次只允许跳过1颗棋子.  写一个程序,首先判断是否可以完成任务.如果可以,输出最少需要的跳动次数. Input 第一行包含三个整数,表示当前棋子的位置a