CSU1021: 组合数末尾的零

题目链接: 点击打开链接
题中所求是C( m, n)转换为二进制数后,其末尾有多少个0,我们可以利用公式C( m, n) = m!/(( m - n)! n!) 将C( m, n) 直接求出来,然后将其对2取余,如果余数为0,就说明它的二进制数有一个0,然后将其除2再对2取余,如此循环直到余数不为0,考虑到C( m, n) 可能很大,我们可以使用Java中的BigInteger类来实现:
import java.util.*;
import java.math.BigInteger;
import java.text.DecimalFormat;
public class Main {
 
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner cin = new Scanner(System.in);
        int T = cin.nextInt();
        while(T!=0)
        {
            T--;
            int m = cin.nextInt();
            int n = cin.nextInt();
            BigInteger s1 = BigInteger.valueOf(1);
            BigInteger s2 = BigInteger.valueOf(1);
            BigInteger s3 = BigInteger.valueOf(1);
            for(int i=1;i<=m;i++)
            {
                BigInteger x = BigInteger.valueOf(i);
                 s1 = s1.multiply(x);
            }
            for(int i=1;i<=m-n;i++)
            {
                BigInteger x = BigInteger.valueOf(i);
                s2 = s2.multiply(x);
            }
            for(int i=1;i<=n;i++)
            {
                BigInteger x = BigInteger.valueOf(i);
                s3 = s3.multiply(x);
            }
            BigInteger sum = s1.divide(s2.multiply(s3));
            int result = 0;
            while(sum.remainder(BigInteger.valueOf(2))==BigInteger.ZERO)
            {
                result++;
                sum = sum.divide(BigInteger.valueOf(2));
            }
            System.out.println(result);
        }
    }
 
}


当然我们可以不必将C( m, n) 完全算出来,因为C( m, n) = m!/(( m - n)! n!) ,就可以将C( m, n) 分为m!、(m-n)!、n!三部分,K!又可以看成K个数,可以通过循环来对这K个数取余除2直到不能再取,此时就不会出现大整数了:
import java.util.*;
import java.math.BigInteger;
import java.text.DecimalFormat;
public class Main {
     
     
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        class C
        {
            public int CC(int m)
            {
                int sum = 0;
                for(int i=1;i<=m;i++)
                {
                    int x = i;
                    while(x%2==0)
                    {
                        sum++;
                        x /= 2;
                    }
                }
                return sum;
            }
        }
        Scanner cin = new Scanner(System.in);
        int T = cin.nextInt();
        while(T!=0)
        {
            T--;
            int m = cin.nextInt();
            int n = cin.nextInt();
            C t = new C();
            int s1 = t.CC(m);
            int s2 = t.CC(m-n);
            int s3 = t.CC(n);
            System.out.println(s1-s2-s3);
        }
    }
 
}
 

当然,用C++实现更简单,更快:
#include <cstdio>
#include <iostream>
 
using namespace std;
 
int C(int m)
{
    int sum = 0;
    for(int i=2;i<=m;i++)
    {
        int x = i;
        while(x%2==0)
        {
            sum++;
            x /= 2;
        }
    }
    return sum;
}
 
int main(void)
{
    int T;
    cin>>T;
    while(T--)
    {
        int n,m;
        cin>>m>>n;
        cout<<C(m)-C(m-n)-C(n)<<endl;
    }
}

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值