bzoj2144 跳跳棋 二分&lca 神题
来源:互联网 发布:清华大学ipv6网络电视 编辑:程序博客网 时间:2024/05/02 02:57
这绝对是一道超级神题!!(表示自己智商低想不到/(ㄒoㄒ)/~~)。
对于状态(x,y,z),看一下它能走到什么:
中间的向外面跳->(2*x-y,x,z) ->(x,z,2*z-y);两边往中间跳:当y-x≠z-y时合法,不妨设y-x>z-y,那么->(y,2*y-x,z)。
可以看到,不考虑特殊情况,往中间跳有一种情况;往两边跳有两种情况;
可以发现,对于(x,y,z)往两边跳得到的状态(u,v,w),那么(x,y,z)同样是(u,v,w)往中间跳得到的状态!
那么,我们将(u,v,w)往中间跳得到的状态(x,y,z)作为(u,v,w)的父亲,那么所有的状态刚好构成了一颗树!
然后答案就变成了求树上两点的距离!
(完了有点激动打了好多回车啊)回想一下普通的树上两点距离,需要得到两点的lca;更一般的需要快速得到某一个点的祖先,那么现在看一下在这道题目中,如何得到一个状态的祖先,即状态(x,y,z)往中间跳k步得到的状态。
如果直接向中间跳k步显然超时的;那么不妨令a=y-x,b=z-y,不妨设a>b,那么显然(x,y,z)的父亲(u,v,w),满足v-u=a-b,w-v=b,定义状态(a,b)可以转移到状态(a-b,b)。那么显然每一个状态(x,y,z)对应唯一一个(a,b),我们发现了什么?如果a>b,那么(a,b)->(a-b,b)或(a,b-a),那么难道不可以用取模来加速运算吗?即(a,b)->(a%b,b)或(a,b%a),刚好和求gcd一样!因此这么做就变成O(log2b)了!
于是我们可以用O(log2k)的时间得到状态(x,y,z)往中间跳k步得到的状态;那么,我们首先判断初始状态和目标状态是否在一颗树中(即根节点是否相同),如果不同输出"NO";否则,回忆倍增求lca的过程,类似的我们可以把初始状态和目标状态先提到同一个深度,然后二分它们到其lca的距离,就可以解决辣!!
时间复杂度O(log^2N)。
AC代码如下:
#include<iostream>#include<cstring>#include<cstdio>#define inf 1000000000using namespace std;int len,k;struct node{int x,y,z;void init(){scanf("%d%d%d",&x,&y,&z);if (y<x) swap(x,y); if (z<x) swap(x,z); if (z<y) swap(y,z);}}a,b,p,q;bool eql(node u,node v){return u.x==v.x && u.y==v.y && u.z==v.z;}node getfa(node t,int rst){for (len=0; rst; len+=k){int u=t.y-t.x,v=t.z-t.y;if (u==v) return t;if (u<v){k=min((v-1)/u,rst);t.x+=k*u; t.y+=k*u; rst-=k;} else{k=min((u-1)/v,rst);t.y-=k*v; t.z-=k*v; rst-=k;}}return t;}int main(){a.init(); b.init();p=getfa(a,inf); int len1=len;q=getfa(b,inf); int len2=len;if (!eql(p,q)){ puts("NO"); return 0; }if (len1<len2){ swap(a,b); swap(len1,len2); }a=getfa(a,len1-len2);int l=0,r=len2,mid;while (l<r){mid=(l+r)>>1;if (eql(getfa(a,mid),getfa(b,mid))) r=mid; else l=mid+1;}printf("YES\n%d\n",(l<<1)+len1-len2);}
by lych
2016.3.4
- bzoj2144 跳跳棋 二分&lca 神题
- bzoj2144 跳跳棋 二分+lca
- [bzoj2144]跳跳棋 LCA
- 【BZOJ2144】跳跳棋 模拟gcd以及倍增LCA
- 【BZOJ2144】跳跳棋
- 【杂题】bzoj2144跳跳棋
- 【bzoj2144】跳跳棋
- [bzoj2144]: 跳跳棋
- 【bzoj2145】【跳跳棋】【二分+lca】
- bzoj2144 LCA+二分
- [BZOJ]2144: 跳跳棋 二分+LCA
- bzoj2144 【国家集训队2011】跳跳棋
- BZOJ 2144 跳跳棋(LCA+欧几里德+二分答案)
- 【LCA】bzoj 2144:跳跳棋
- bzoj 2144: 跳跳棋 lca+倍增
- A1229. 跳跳棋(何朴藩) 思路题 LCA
- BZOJ 2144 跳跳棋 (lca 模型转换)
- 2144: 跳跳棋
- 第四届蓝桥杯 软件类省赛真题 第九题:买不到的数目
- C++学习笔记:类型转换dynamic_cast和reinterpret_cast
- 数据库事务
- webview清理缓存
- poj2253Frogger——最短路变形
- bzoj2144 跳跳棋 二分&lca 神题
- pb程序在64位操作系统上使用Instant Client 连接oracle数据库
- Android之Lollipop DevicePolicyManager学习(下)
- 支持向量机(SVM)算法
- iOS学习之 - Range
- 技术负责人的三种角色
- python中xrange用法
- 图像处理中矩形标记图像中某一块区域matlab中rectangle函数介绍
- 数字三角形