ZOJ3987(二进制枚举+java大数)

来源:互联网 发布:人工智能招聘信息 编辑:程序博客网 时间:2024/05/18 16:36

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3987

题意:给一个数n和一个数m,让你将n这个数分成m个数相加,且这m个数的or值最小。

思路:直接从二进制角度考虑,要使得m个数的or值最小,也就是说m个数中最高位应该尽量低,我们先假设存在一个k使得

(2^k-1)*m > n > (2^(k-1)-1)*m,那么可以知道m个二进制数中至少有一个数的最高位为k。因为现在我们做或运算,所以此时应让尽量多的数的第k位为1,那么答案ans += 2^k,从高位向低位递推,直到n变为0即可。

代码:

import java.util.*;import java.math.*;public class Main{    public static void main(String[] args){        Scanner cin=new Scanner(System.in);        int T=cin.nextInt();        while(T-->0){            BigInteger n=cin.nextBigInteger();            BigInteger m=cin.nextBigInteger();            BigInteger ans=BigInteger.valueOf(0);            BigInteger nn=n;            int len=0;            while(nn.compareTo(BigInteger.ZERO)>0){                nn=nn.divide(BigInteger.valueOf(2));                len++;            }            for(int i=len-1;i>=0;i--){                BigInteger num1=BigInteger.valueOf(2).pow(i).subtract(BigInteger.ONE);                BigInteger num2=num1.multiply(m);                while(num2.compareTo(n)<0){                    BigInteger num3=n.divide(BigInteger.valueOf(2).pow(i));                    if(num3.compareTo(m)>0) num3=m;                    n=n.subtract(BigInteger.valueOf(2).pow(i).multiply(num3));                    ans=ans.add(BigInteger.valueOf(2).pow(i));                }            }            System.out.println(ans);        }    }}


原创粉丝点击