ZOJ 3987 Numbers (大数+贪心)

Numbers

Time Limit:2 Seconds      Memory Limit: 65536 KB

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
 
3312000125
题意:
给你一个数n,要你把它分成m个数a1,a2,a3,...am(a1+a2+...+am=n),使得a1|a2|a3|a4|...|am最小
解析:
这道题就是从n的二进制最高位一步一步向低位移贪心答案,贪心的时候,因为要求是min,所以要尽可能的放0,当不得不放1的时候,就只能放1
这个不得不的条件就是这一位k:(2^k-1)*m<n,说明第k位这个位置在a1...am中一定有有一个是1,即答案的第k位为1,然后既然第k位已经有1了,那么就
那么就要多放几个,这样后面就可以少放点。那么就要求出最多有多少数第k位能放1=min(m,n/2^k),然后n减去这个数,递归处理就可以了
import java.math.*;
import java.util.*;

public class Main {

	
	public static BigInteger n,m;
	
	public static void solve()
	{
		BigInteger ck=BigInteger.ONE;
		int up=0;
		while(ck.compareTo(n)<=0)
		{
			ck=ck.shiftLeft(1);
			up++;
		}
		ck=ck.shiftRight(1);
		up--;
		BigInteger ans=BigInteger.ZERO;
		for (int i=up;i>=0;i--)
		{
			BigInteger cc=BigInteger.valueOf(2).pow(i);
			BigInteger bei=n.divide(cc);
			if (cc.subtract(BigInteger.ONE).multiply(m).compareTo(n)<0)
			{
				if(bei.compareTo(m)>=0)
				{
					n=n.subtract(m.multiply(cc));
					ans=ans.add(cc);
				}
				else
				{
					n=n.subtract(bei.multiply(cc));
					ans=ans.add(cc);
				}
			}
		}
		System.out.println(ans);
		
	}
	
	
	
	public static void main (String[] args)
	{
		Scanner sc=new Scanner(System.in);
		while(sc.hasNextInt())
		{
			int t=sc.nextInt();
			for (int k=0;k<t;k++)
			{
				n=sc.nextBigInteger();
				m=sc.nextBigInteger();
				solve();
			}
		}
	}
}
python:

while(True):
    try:
        t=int(input())
        for k in range(0,t):
            n,m=raw_input().strip().split()  #strip将收尾的空格符,换行符去掉
            n=int(n)             #split 将字符串按空字符(空格、换行(\n)、制表符(\t))分离成独立的字符串放入列表
            m=int(m)
            c=1
            while(c<=n):
                c<<=1
            c>>=1
            ans=0
            while(c>0):
                if (c-1)*m < n:
                    if(n//c>=m):
                        n-=m*c
                        ans+=c
                    else:
                        n-=n//c*c
                        ans+=c
                    #print('n:'+repr(n)+'c:'+repr(c)+'flag:'+repr(flag)+'ans:'+repr(ans))
                c=c>>1
                #print('c'+repr(c))
            print(ans)
                			
    except:
		break


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值