zoukankan      html  css  js  c++  java
  • luogu P1852 [国家集训队]跳跳棋

    luogu

    直接操作是不可能的,考虑发现一些性质.可以发现如果每次跳的棋子都是两边的,那么最多只有一种方案,那么就把这样操作得到的状态记为当前状态的父亲,从一个状态这样做一定会结束.那么如果两个状态只操作两边到达的最终状态相同,那么就可以互相转换

    步数的话,如果把这个看成一棵树,那么就是一个树上距离问题,就要求出这两个状态在树上的深度以及他们lca的深度.这个操作直接模拟是不行的,不过如果把中间的棋子坐标和左边坐标差记为(a),右边的和中间的差记为(b)(这里假设(a>b),反之类似),那么每次操作后会得到((a-b,b)),操作若干次后得到((amod b,b))(如果(b|a)就是((b,b))),然后会进行反向操作直到(a=b),所以每次只要从((a,b))走到((amod b,b))就好了,最多只会走(log n)次,然后到达根的距离也可以顺带算出来.lca的话就把两个状态的父亲按顺序记到栈里,每次弹栈顶弹到最后一个相同元素,不过注意可能真正的lca可能并不是((amod b,b)),所以还要稍微讨论一下

    #include<bits/stdc++.h>
    #define LL long long
    #define uLL unsigned long long
    #define db double
    
    using namespace std;
    const int inf=1<<30;
    int rd()
    {
    	int x=0,w=1;char ch=0;
    	while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    	return x*w;
    }
    struct node
    {
    	int x,y,z;
    	node(){}
    	node(int nx,int ny,int nz)
    	{
    		x=nx,y=ny,z=nz;
    		if(x>y) swap(x,y);
    		if(y>z) swap(y,z);
    		if(x>y) swap(x,y);
    	}
    	bool operator == (const node &bb) const {return x==bb.x&&y==bb.y&&z==bb.z;}
    }s1[50],s2[20];
    int d1[50],d2[50],t1,t2,ans;
    node getfa(node aa)
    {
    	int l1=aa.y-aa.x,l2=aa.z-aa.y;
    	if(l1==l2) return node(-inf,-inf,-inf);
    	if(l1<l2)
    	{
    		bool o=l2%l1==0;
    		int dt=o?l1:0;
    		ans+=l2/l1-o;
    		return node(aa.z-dt-l2%l1-l1,aa.z-dt-l2%l1,aa.z);
    	}
    	else
    	{
    		bool o=l1%l2==0;
    		int dt=o?l2:0;
    		ans+=l1/l2-o;
    		return node(aa.x,aa.x+dt+l1%l2,aa.x+dt+l1%l2+l2);
    	}
    }
    
    int main()
    {
    	s1[0].x=-inf,s2[0].x=-inf-1;
    	s1[++t1]=node(rd(),rd(),rd());
    	s2[++t2]=node(rd(),rd(),rd());
    	while(s1[t1].x>-inf) ++t1,s1[t1]=getfa(s1[t1-1]);
    	--t1;
    	while(s2[t2].x>-inf) ++t2,s2[t2]=getfa(s2[t2-1]);
    	--t2;
    	if(!(s1[t1]==s2[t2])) {puts("NO");return 0;}
    	puts("YES");
    	while(s1[t1-1]==s2[t2-1])
    	{
    		--t1,--t2;
    		int l1=s1[t1].y-s1[t1].x,l2=s1[t1].z-s1[t1].y;
    		if(l1<l2) ans-=2*(l2/l1-(l2%l1==0));
    		else ans-=2*(l1/l2-(l1%l2==0));
    	}
    	--t1,--t2;
    	if(t1&&t2)
    	{
    		if(s1[t1].x==s2[t2].x)
    		{
    			int b=s1[t1].z-s1[t1].y,a=min(s1[t1].y-s1[t1].x,s2[t2].y-s2[t2].x)-(s1[t1+1].y-s1[t1+1].x);
    			ans-=2*(a/b);
    		}
    		else if(s1[t1].z==s2[t2].z)
    		{
    			int b=s1[t1].y-s1[t1].x,a=min(s1[t1].z-s1[t1].y,s2[t2].z-s2[t2].y)-(s1[t1+1].z-s1[t1+1].y);
    			ans-=2*(a/b);
    		}
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    [转载]VC补遗之Profile篇
    [原创]百度之星2009初赛第二场第四题解答
    [总结]QT在CODE:BLOCKS中的配置
    [原创]自己写的一个简单的程序日志记录类
    [原创]QT动态加载UI文件注意事项
    window版本信息资源格式
    [原创]滚动条滚动范围的问题总结
    ofstream奇怪问题解决方法
    [转载]最小矩形(rec1)的解题报告
    oracle数据库用户之间授权
  • 原文地址:https://www.cnblogs.com/smyjr/p/11360896.html
Copyright © 2011-2022 走看看