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} 2i−1(注意从 2 0 2^0 20开始的),那么我们知道第一个比它小的数是 2 i − 1 − 1 2^{i-1}-1 2i−1−1即这一位后面的位全为1的情况,我们比较一下如果m个数全都这样的数,(就是全为1),这m个数的和如果还比当前n小,说明我们必须至少得要有一个i位为1,这样才能凑成n嘛,否则就凑不成了。
这样如果我们判断了当前i位必须有一个1(有一个 2 i − 1 2^{i-1} 2i−1),即( m × ( 2 i − 1 − 1 ) < n m\times (2^{i-1}-1) < n m×(2i−1−1)<n),此时我们就让i位上尽可能的多放1,那么能放多少个呢
当然就是 n u m = n 2 i − 1 num = \frac{n}{2^{i-1}} num=2i−1n了,当然了如果 n u m > m num > 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×2i−1,答案此时就要加上这个 2 i − 1 2^{i-1} 2i−1,然后剩下的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);
}
}
}