ZOJ 3987 Numbers (贪心+JAVA大数)

本文介绍了一种解决将大整数n分割成m个非负整数之和,以求这些整数的最小或值的问题的算法。通过合理分配余数和枚举最高位,确保了分割后的整数或值最小化。

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

3
3
1
2000
125

题意:

给你两个大数n,m,让你把n分成m个数的和,求这m个数的最小或值。

容易想到先平分成n/m,然后在尽可能不增加最高位的情况下添加余数。

这样最高位就确定了。

然后这个数不会超过2的5000次方。(其实4000次方就够了)

直接从最高位依次枚举,看看m个数的这一位能不能全为0即可。

代码:(第一个正式赛模拟赛上AC的java代码,鼓掌!!!下周还得考试。。。)

import java.math.*;
import java.util.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Scanner;
public class Main {
	public static BigInteger poww(BigInteger n,BigInteger m) {
        BigInteger bigN = n;
        BigInteger bigM = m;
        BigInteger result = BigInteger.ONE;
        for (BigInteger i = BigInteger.ONE; i.compareTo(bigM) <= 0; i = i.add(BigInteger.ONE)) {
            result = result.multiply(bigN);
        }
        return result;
	}
	public static void main(String[] args) {
	Scanner sc = new Scanner(System.in);
	//result.toString();
	int T,cas=1;
	BigInteger n=new BigInteger("1");
	BigInteger m=new BigInteger("1");
	BigInteger k=new BigInteger("1");
	BigInteger x=new BigInteger("1");
	BigInteger y=new BigInteger("1");
	BigInteger[] tmp=new BigInteger[5010];
	BigInteger two=new BigInteger("2");
	BigInteger one=new BigInteger("1");
	BigInteger zero=new BigInteger("0");
	BigInteger ans=new BigInteger("0");
	tmp[0]=one;
	for(int i=1;i<5010;i++)
	tmp[i]=tmp[i-1].multiply(two);
	T=sc.nextInt();
	int cnt;
	while(T>0)
	{
		T--;
		n=sc.nextBigInteger();
		m=sc.nextBigInteger();
		x=n.divide(m);
		y=n.mod(m);
		cnt=0;ans=zero;
		while(tmp[cnt].compareTo(x)<0||(tmp[cnt].equals(x)&&zero.compareTo(y)<0))
		{
			cnt++;
		}
		BigInteger a=tmp[cnt].subtract(one);
		if(zero.compareTo(y)<0&&a.equals(x)) cnt++;
		//System.out.println("  *    "+cnt);
		for(int i=cnt;i>=0;i=i-1)
		{
			a=tmp[i].multiply(m).subtract(m);
			if(a.compareTo(n)<0) {
			a=tmp[i].multiply(m);
			if(n.compareTo(a)<0)
			{
				a=n.divide(tmp[i]);
				if(a.equals(zero)) continue;
				a=tmp[i].multiply(a);
				n=n.subtract(a);
				ans=ans.add(tmp[i]);
				continue;
			}
			else
			{
				ans=ans.add(tmp[i]);
				n=n.subtract(a);
				if(n.equals(zero)) break;
			}
			}
		}
		System.out.println(ans.toString());
	}
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值