转载请注明出处: http://www.cnblogs.com/fraud/ ——by fraud
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 125536/65536 K (Java/Others)
Total Submission(s): 775 Accepted Submission(s): 228
题意:
给出三个点数轴上的起始为止与终止位置,问能否通过不断的跳跃从起始位置到终止位置(ps:不需要一一对应),每次跳跃时不得跨过两个点,若能,则给出最少需要几次操作
分析:
不妨设a<b<c,x<y<z。
由于一次不能跨越两个点。若b-a>c-b,则只能进行(1)b->2a-b-a或者(2)b->2c-b或者(3)a->2b-a;
若b-a<c-b,则只能进行(1)b->2a-b-a或者(2)b->2c-b或者(3)c->2b-c;
若b-a=c-b,则只能进行(1)b->2a-b-a或者(2)b->2c-b;
我们可以发现,若每次选取(1)(2)操作,则三个数在数轴上的跨度会不断变大,我们可以视为其分别向左儿子和右儿子移动,
若选取(3)操作,则三个数在数轴上的跨度会不断变小,对此,我们可以将其视为向父亲结点移动(因为对于每种状态,其对应的(3)操作是唯一的,这恰好对应这树的父亲结点是唯一的)。
通过一定次数的向父亲结点移动,我们可以发现最终一定会变成第三种状态。也就是对于判断yes还是no,我们只需要判断其所对应的根节点是否相同,若不同,则必定不能从初始状态转移到最终状态。
那么,如何快速地求出某一状态进行若干操作之后的状态呢?
我们假设a<b<c,并且c-b>a-b。那么,一次(3)操作之后会变成b,2b-a,c。也就是相当于给a和b同时加上了b-a。那么对于这样需要移动几次呢?(c-b)/(b-a)?
这是不对的,例如1,2,4。若移动二次,则会变成3,4,4。也就是我们要避免b-a=c-b的发生。即对于(c-b)%(b-a)==0时,我们需要少移一次。
于是,利用向下取整的特性,我们可以发现只要移(c-b-1)/(b-a)次。
如此,不断往复,我们就可以快速地求出移动若干次的状态,然后二分搞一下就行了
1 //##################### 2 //Author:fraud 3 //Blog: http://www.cnblogs.com/fraud/ 4 //##################### 5 #include <iostream> 6 #include <sstream> 7 #include <ios> 8 #include <iomanip> 9 #include <functional> 10 #include <algorithm> 11 #include <vector> 12 #include <string> 13 #include <list> 14 #include <queue> 15 #include <deque> 16 #include <stack> 17 #include <set> 18 #include <map> 19 #include <cstdio> 20 #include <cstdlib> 21 #include <cmath> 22 #include <cstring> 23 #include <climits> 24 #include <cctype> 25 using namespace std; 26 #define XINF INT_MAX 27 #define INF 0x3FFFFFFF 28 #define MP(X,Y) make_pair(X,Y) 29 #define PB(X) push_back(X) 30 #define REP(X,N) for(int X=0;X<N;X++) 31 #define REP2(X,L,R) for(int X=L;X<=R;X++) 32 #define DEP(X,R,L) for(int X=R;X>=L;X--) 33 #define CLR(A,X) memset(A,X,sizeof(A)) 34 #define IT iterator 35 typedef long long ll; 36 typedef pair<int,int> PII; 37 typedef vector<PII> VII; 38 typedef vector<int> VI; 39 #define MAXN 10 40 ll a[MAXN],b[MAXN]; 41 ll ra[MAXN],rb[MAXN]; 42 void gcd(ll *x,ll &d){ 43 ll l1=x[1]-x[0]; 44 ll l2=x[2]-x[1]; 45 ll t; 46 while(l1!=l2){ 47 if(l1<l2){ 48 t=(l2-1)/l1; 49 ll tmp=t*l1; 50 x[0]+=tmp; 51 x[1]+=tmp; 52 }else{ 53 t=(l1-1)/l2; 54 ll tmp=t*l2; 55 x[1]-=tmp; 56 x[2]-=tmp; 57 } 58 d+=t; 59 l1=x[1]-x[0]; 60 l2=x[2]-x[1]; 61 //gcd(x,d); 62 } 63 } 64 void gao(ll *x,ll d){ 65 ll l1=x[1]-x[0]; 66 ll l2=x[2]-x[1]; 67 ll t; 68 while(d>0){ 69 if(l1<l2){ 70 t=(l2-1)/l1; 71 if(t>d)t=d; 72 ll tmp=t*l1; 73 x[0]+=tmp; 74 x[1]+=tmp; 75 }else { 76 t=(l1-1)/l2; 77 if(t>d)t=d; 78 ll tmp=t*l2; 79 x[1]-=tmp; 80 x[2]-=tmp; 81 } 82 d-=t; 83 l1=x[1]-x[0]; 84 l2=x[2]-x[1]; 85 } 86 } 87 88 int main() 89 { 90 ios::sync_with_stdio(false); 91 while(scanf("%I64d%I64d%I64d",&a[0],&a[1],&a[2])!=EOF){ 92 for(int i=0;i<3;i++)scanf("%I64d",&b[i]); 93 sort(a,a+3); 94 sort(b,b+3); 95 for(int i=0;i<3;i++)ra[i]=a[i]; 96 for(int i=0;i<3;i++)rb[i]=b[i]; 97 ll d1=0,d2=0; 98 bool flag=0; 99 for(int i=0;i<2;i++)if(ra[i]==ra[i+1])flag=1; 100 for(int i=0;i<2;i++)if(rb[i]==rb[i+1])flag=1; 101 if(flag){ 102 printf("NO\n"); 103 continue; 104 } 105 gcd(ra,d1); 106 gcd(rb,d2); 107 flag=0; 108 for(int i=0;i<3;i++) 109 if(ra[i]!=rb[i])flag=1; 110 if(flag){ 111 printf("NO\n"); 112 continue; 113 } 114 printf("YES\n"); 115 ll ans = 0; 116 ll tmp = 0; 117 if(d1>d2)gao(a,d1-d2); 118 else gao(b,d2-d1); 119 ll l=0,r=min(d1,d2); 120 while(l<=r){ 121 ll mid=(l+r)>>1; 122 for(int i=0;i<3;i++)ra[i]=a[i]; 123 for(int i=0;i<3;i++)rb[i]=b[i]; 124 gao(ra,mid); 125 gao(rb,mid); 126 bool flag=0; 127 for(int i=0;i<3;i++) 128 if(ra[i]!=rb[i])flag=1; 129 if(!flag){ 130 tmp=mid; 131 r=mid-1; 132 }else { 133 l=mid+1; 134 } 135 } 136 printf("%I64d\n",tmp*2+max(d1-d2,d2-d1)); 137 } 138 return 0; 139 }