首页 > 试题广场 >

排列与二进制

[编程题]排列与二进制
  • 热度指数:4168 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 64M,其他语言128M
  • 算法知识视频讲解
在组合数学中,我们学过排列数。从n个不同元素中取出m(m<=n)个元素的所有排列的个数,叫做从n中取m的排列数,记为p(n, m)。具体计算方法为p(n, m)=n(n-1)(n-2)……(n-m+1)= n!/(n-m)! (规定0!=1).当n和m不是很小时,这个排列数是比较大的数值,比如  p(10,5)=30240。如果用二进制表示为p(10,5)=30240=( 111011000100000)b,也就是说,最后面有5个零。我们的问题就是,给定一个排列数,算出其二进制表示的后面有多少个连续的零。

输入描述:
输入包含多组测试数据,每组测试数据一行。
每行两个整数,n和m,0<m<=n<=10000,n=0标志输入结束,该组数据不用处理。


输出描述:
对于每个输入,输出排列数p(n, m)的二进制表示后面有多少个连续的零。每个输出放在一行。
示例1

输入

10 5
6 1
0 0

输出

5
1

有没有路过的大神帮忙分析一下,我这代码明明不会出现分母为零的情况,牛客OJ还给我报出了以下异常:

图片说明

IDE上完全没问题

import java.util.Scanner;

public class Main {
    public static void main(String[] args) throws ArithmeticException {
        Scanner scan = new Scanner(System.in);
        while (scan.hasNext()) {
            int n = scan.nextInt();
            int m = scan.nextInt();
            // 检测到n为零,返回
            if (n == 0) {
                return;
            }
            // 根据公式得到p
            int p = factorial(n) / factorial(n - m);
            // 将p转成二进制串
            String str = Integer.toBinaryString(p);
            // 逆向字符串,为了得到后面连续的0的个数
            String reverse = new StringBuilder(str).reverse().toString();
            int count = 0;
            for (int i = 0; i < reverse.length(); i++) {
                if (reverse.charAt(i) == '0') {
                    count++;
                }
                else {// 第一次遇到1就break,此时的count已经是答案
                    break;
                }
            }
            System.out.println(count);// 输出count,即是答案
        }
    }

    // 递归计算阶乘
    private static int factorial(int n) {
        // TODO Auto-generated method stub
        if (n == 0 || n == 1) {
            return 1;
        }
        else {
            return n * factorial(n - 1);
        }
    }
}

已换其他思路通过了OJ,希望有大神帮我分析一下以上代码,是牛客的什么BUG?

编辑于 2018-05-15 11:12:42 回复(0)
有题目中的公式p(n, m)=n(n-1)(n-2)……(n-m+1)= n!/(n-m)! ,根据数学 阶乘算最后得到的p(n,m)=n*(n-1)*(n-2)*(n-3)........*(n-m+1)。比如p(10,5)=10*9*8*7*6*5*4*3*2*1/5*4*3*2*1=10*9*8*7*6;也就是相当于求 10*9*8*7*6 中最后连续0的个数。
   由于 二进制数乘法过程可仿照十进制数乘法进行。但由于二进制数只有0或1两种可能的乘数位,导致二进制乘法更为简单。二进制数乘法的法则为:


0×0=0
0×1=1×0=0
1×1=1


例如:1001和1010相乘的过程如下:



由低位到高位,用乘数的每一位去乘被乘数,若乘数的某一位为1,则该次部分积为被乘数;若乘数的某一位为0,则该次部分积为0。某次部分积的最低位必须和本位乘数对齐,所有部分积相加的结果则为相乘得到的乘积。

由于二进制乘法和十进制乘法相似的原理,可知 只需要求出每位数中最后零的个数,然后把每位零的个数相加就是最后连续零的结果。

import java.util.Scanner;
public class Main
{
    public static void main(String[] args)
    {
        Scanner in=new Scanner(System.in);
        while(in.hasNextInt())
        {  
            int n=in.nextInt();
            int m=in.nextInt();
            if(n==0)
                break;
            int res=0;
            for(int i=n-m+1;i<=n;++i)
            {
                int tmp=i;
                while((tmp&1)==0)
                {
                    ++res;
                    tmp>>=1;
                }
            }
            System.out.println(res);
        }
        in.close();
    }
}



发表于 2016-08-25 14:42:19 回复(4)

问题信息

难度:
2条回答 6140浏览

热门推荐

通过挑战的用户

查看代码