zoukankan      html  css  js  c++  java
  • SGU 126 Boxes(模拟题|二进制)

    Translate:Sgu/126

    126. 盒子

    time limit per test: 0.5 sec.

    memory limit per test: 4096 KB


    有两个盒子. 第一个盒子里有A 个球, 第二个里面有B 个球 (0 < A + B < 2147483648). 允许把球在两个盒子间移动. 从一个盒子向另一个盒子移动球的数目必须等

    于接受盒子现有的球的数量. 你需要搞清楚, 最后球能不能都移动到一个盒子里


    Input

    第一行两个整数 A 和 B, 空格分隔.


    Output

    一行数字 N – 需要移动的次数,如果不存在,输出-1


    Sample Input

    2 6

    Sample Output

    2

    数学解法

    一个二进制的数学题

    原题:狠狠地打我!

    想法:这题是一道数学题,裸的。

              原理是二进制,这道题的解法是:先将两数变得互质,即都除去最大公约数,再判断,若相加为2的k次幂则有解,否则无解。

              证:首先,我们是要使两数相等,则其步骤数显然只与相对大小有关,因为,转移的数量时刻只与较小数大小有关,且只有加减法参与,两数的最大公约数不会变小,因而约去和不约效果一致。

              其次,证明互质时,有解当且仅当相加为2的k次幂:

                      充分性:若满足两数和为2的k次幂,则,可以转换角度看待一个

                                    操作:

                                           操作的过程是,在二进制下,将较小的数,向左移

                                          一位,而较大的数随之变化。这样,我们将看到,

                                          较小数,无论是谁,右边的连续零位将不断增加,

                                          且较大的数也必然如此,因为两者低位每位相加必

                                          须为零。这样每个操作就是不断将右边的连续零位

                                          不断加长,到后面时,必然会出现,零位为k-1个,

                                          第k位为1。

                      必要性:若不满足,则,和中至少有一位为1,那么,不妨考虑最右

                                    边的那个,那么,若其是0+1得来,则,较小数无论是谁,

                                    左移都不可以使得两数相等,因为,相等就必须是该位的右

                                    一位两数同时为一,而左移会使那一位变为0,矛盾。若为

                                   两个低位的1相加而来,则操作后,较小数那位的1消失,又

                                   变为0+1形式,所以,这时,两数永远不可能相等,就不会

                                   达到一个为0。

              那么,怎样快速的计算步骤数呢?

              由于有解的且互质的两个数二进制下,最右边的“1”的位置相同,所以一次操作只能移动一个位置,而我们要将那个“1”移到k+1位,所以,最后的结果是

              log2(a+b)-log2(a and -a)

              注意,好像SGU用这个式子会RE on 3……


    #include <stdio.h>
    using namespace std;
    
    int gcd(int a, int b)
    {
        return b?gcd(b,a%b):a;
    }
    int main()
    {
    	int a, b;
        scanf("%d%d", &a, &b);
        int s = (a+b)/gcd(a, b), res = 0;
        while (!(s & 1)) 
        {
              s /= 2;
              res++;
        }
        if (s == 1) printf("%d", res);
           else     printf("-1");    
        return 0;
    }


    模拟解法

    首先我们需要知道,求 A,B 的步数其实就等同于求 A/gcd(A,B),B/gcd(A,B) 的步数。

    对于这个的证明很明显,每次移动的求一定是 gcd(A,B) 的倍数。

    对于每次移动,令 A = A/gcd(A,B) ,B = B/gcd(A,B),讨论情况 :

    (1) A,B都为偶数(不可能)

    (2) A,B有一个为奇数 (无解,很明显吧,因为A+B都是奇数了)

    (3) A,B都是奇数-> 假设A是较小的那一个,那么就可以变化为 A*2,B-A ,然后我们的新目标就变成了求解 A*2,B-A 的步数

    结束条件 A=0 或 B=0

    容易证明,上述步骤重复次数最多不超过 log(A+B)次


    #include<iostream>
    using namespace std;
    int gcd(int a,int b)
    {
    	if(b!=0) return gcd(b,a%b);
    	return a;
    }
    int A0,B0;
    int solve(int A,int B)
    {
    	if(!A||!B) return 0;
    	int t=gcd(A,B);
    	A/=t;B/=t;
    	if(!(A%2==1&&B%2==1)) return -1;
    	if(A>B) swap(A,B);
    	t=solve(A*2,B-A);
    	return t==-1?-1:t+1;
    }
    int main()
    {
    	cin>>A0>>B0;
    	cout<<solve(A0,B0);
    	return 0;
    }


    版权声明:本文为博主原创文章,未经博主允许不得转载。

    today lazy . tomorrow die .
  • 相关阅读:
    Redis
    Zookeeper的安装配置及基本开发
    【Unity Shader】新书封面 — Low Polygon风格的渲染
    Hive基本原理及环境搭建
    Hadoop开发环境搭建
    java常用排序算法
    企业人事管理系统项目拾金
    Linux27:分区、格式化与修复
    Linux26:查询磁盘和监控系统资源
    Linux25:文件系统特点与XFS文件系统
  • 原文地址:https://www.cnblogs.com/france/p/4808713.html
Copyright © 2011-2022 走看看