Numbers ZOJ - 3987(二进制思维+贪心)

12 篇文章 0 订阅
10 篇文章 0 订阅

Numbers ZOJ - 3987

DreamGrid has a nonnegative integer . He would like to divide into nonnegative integers and minimizes their bitwise or (i.e. and should be as small as possible).
Input

There are multiple test cases. The first line of input contains an integer , indicating the number of test cases. For each test case:

The first line contains two integers and ().

It is guaranteed that the sum of the length of does not exceed .
Output

For each test case, output an integer denoting the minimum value of their bitwise or.
Sample Input

5
3 1
3 2
3 3
10000 5
1244 10

Sample Output

3
3
1
2000
125
题意:

将整数 n n n拆分成 m m m个数的和,输出这 m m m个数的按位或的最小值

分析:

考虑贪心,如果m个数中的某一个数的某一位有一个是1了,那么最终结果这一位也必定是1,因此我们可以判断一下分成的这m个数,这个位是否必须要有一个1,那么如果有,我们就让尽量多的1在这一位,使得后面的1 尽量少,没有的话,我们能不放就不放

那么重点是我们如何去判断这一位是否至少需要一个1呢?

对于一个数n,首先记录n的二进制位数,然后我们从高位到低位一位一位的看

对于当前位i,我们看如果分成m个数后,这个位是否必须要有1,如果这一位有1的话说明得有一个 2 i − 1 2^{i-1} 2i1(注意从 2 0 2^0 20开始的),那么我们知道第一个比它小的数是 2 i − 1 − 1 2^{i-1}-1 2i11即这一位后面的位全为1的情况,我们比较一下如果m个数全都这样的数,(就是全为1),这m个数的和如果还比当前n小,说明我们必须至少得要有一个i位为1,这样才能凑成n嘛,否则就凑不成了。

这样如果我们判断了当前i位必须有一个1(有一个 2 i − 1 2^{i-1} 2i1),即( m × ( 2 i − 1 − 1 ) &lt; n m\times (2^{i-1}-1) &lt; n m×(2i11)<n),此时我们就让i位上尽可能的多放1,那么能放多少个呢

当然就是 n u m = n 2 i − 1 num = \frac{n}{2^{i-1}} num=2i1n了,当然了如果 n u m &gt; m num &gt; m num>m,让 n u m = m num = m num=m,然后更新当前n,即 n − = n u m × 2 i − 1 n -= num \times 2^{i-1} n=num×2i1,答案此时就要加上这个 2 i − 1 2^{i-1} 2i1,然后剩下的n再次循环判断

code:

import java.math.BigInteger;
import java.util.Scanner;
public class Main {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner in = new Scanner(System.in) ;
        BigInteger n,m;
        int T = in.nextInt();
        while((T--) > 0) {
        	n = in.nextBigInteger();
        	m = in.nextBigInteger();
        	int len = 0;
        	BigInteger tmp = n;
        	while(tmp.compareTo(BigInteger.ZERO) > 0) {
        		tmp = tmp.shiftRight(1);
        		len++;
        	}
        	BigInteger ans = BigInteger.ZERO;
        	for(int i = len; i > 0; i--) {
        		if(n.compareTo(BigInteger.ZERO) <= 0) break;
        		tmp = BigInteger.valueOf(2).pow(i-1).subtract(BigInteger.ONE);
        		BigInteger sum = tmp.multiply(m);
        		if(sum.compareTo(n) < 0) {
        			BigInteger num = n.divide(BigInteger.valueOf(2).pow(i-1));
        			if(num.compareTo(m) > 0) num = m;
        			n = n.subtract(BigInteger.valueOf(2).pow(i-1).multiply(num));
        			ans = ans.add(BigInteger.valueOf(2).pow(i-1));
        		}
        	}
        	System.out.println(ans);
        	
        }
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值