ZOJ 3987 Numbers (BigInteger类、贪心)

Numbers


Time Limit: 2 Seconds      Memory Limit: 65536 KB


DreamGrid has a nonnegative integer n. He would like to divide n into m nonnegative integers  and minimizes their bitwise or (i.e.n=a_1 + a_2 + \dots + a_m and a_1 \text{ OR } a_2 \text{ OR } \dots \text{ OR } a_m should be as small as possible).

Input

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

The first line contains two integers  and  (0 \le n < 10^{1000}, 1 \le m < 10^{100}).

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

Author: LIN, Xi
Source: The 2017 China Collegiate Programming Contest, Qinhuangdao Site


题意:n由m个数组成,n=a1+a2+...+am。求a1 or a2 or ...or am的最小值。

思路:将n看作由m个二进制数构成的数,对于这m个数,我们希望它们的二进制为1的位置尽可能的低,因为题目要求或运算的结果尽可能的小。

我们从n的二进制最高位开始遍历,这m个数只有当k位置必须放置1时,我们才在第k位放置1,其他情况放置0。必须放置1的情况为:(2^k-1)*m>=n 并且(2*(k-1)-1)*m<n,表示如果我在k位置不放置1,后面的位置全部放置1也小于n,所以我们至少需要在k位置放置1个1,既然这个位置确定要放置1了,我们就尽可能的多放置1,使得后面放置1的位置尽可能的低,ans=ans+2^k。

因为数据的范围很大,需要用到java的BigInteger类

AC代码:

import java.math.BigInteger;
import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		BigInteger n,m,ans,tmp,num,cnt;
		Scanner sc = new Scanner(System.in);
		int T=sc.nextInt();
		while(T-->0) {
			n = sc.nextBigInteger();
			m = sc.nextBigInteger();
			ans = BigInteger.ZERO;
			tmp = n;
			int len=0;
			while(tmp.compareTo(BigInteger.ZERO)>0) {
				tmp=tmp.divide(BigInteger.valueOf(2));
				len++;
			}
			//组成n的二进制最高位为2^(len-1)
			for(int i=len-1;i>=0;i--) {
				//num1=(2^k-1)*m
				num = BigInteger.valueOf(2).pow(i).subtract(BigInteger.ONE).multiply(m);
				if(num.compareTo(n)<0) {
					cnt = n.divide(BigInteger.valueOf(2).pow(i));
					if(cnt.compareTo(m)>0)
						cnt=m;
					n=n.subtract(BigInteger.valueOf(2).pow(i).multiply(cnt));
					ans=ans.add(BigInteger.valueOf(2).pow(i));
				}
			}
			System.out.println(ans);
		}

	}

}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值