Numbers ZOJ - 3987[思维暴力]

题意:给出一个数字N以及一个M,要求把N分为M部分且满足

  • N = a 1 + a 2 + a 3 + ⋯ + a m N = a_1 + a_2 + a_3 + \dots+a_m N=a1+a2+a3++am
    询问如何让 a 1 ∣ a 2 ∣ a 3 ∣ … ∣ a m a_1|a_2|a_3|\dots|a_m a1a2a3am尽可能的小,输出最小值。

题解:如果让后来的或值最小的话,那么我们首先需要去掉最高位的1(二进制下),然后我们的工作就成为了从高到低判断某一位是否放1,我们在判断某一位的时候我们需要判断他后面的数字如果全部为1的时候是否比N还要大,如果可以的话,这一位可以不放1,否则的一定要放1,该位放1,那么相应的其他(m-1)个数字也要放1(让N尽量的小),然后统计答案即可。(大数不可少


收获:转化为一个较为容易实现的问题,如判断某位是否要放1


a c   c o d e : ac\ code: ac code:

import java.util.*;
import java.math.*;


public class Main {
	static BigInteger n, m, two = BigInteger.valueOf(2), one = BigInteger.ONE;
	static BigInteger []num = new BigInteger[4000];
	static int top;
	public static void solve() {
		BigInteger ans = BigInteger.ZERO;
		for(int i = 0; i < top; i++) {
			int pos = top - 1 - i;
			BigInteger dig = two.pow(pos);
			dig = dig.subtract(one);
			dig = dig.multiply(m);
			if(dig.compareTo(BigInteger.ZERO) < 0) {
				dig = BigInteger.ZERO;
			}
			//System.out.println(dig + " " + n);
			BigInteger ttt = BigInteger.ZERO;
			if(dig.compareTo(n) < 0) {
				ans = ans.add(two.pow(pos));
				BigInteger x = two.pow(pos);
				BigInteger k = n.divide(x);
				if(k.compareTo(m) > 0) {
					k = m;
				}
				n = n.subtract(k.multiply(x));
			}
		}
		System.out.println(ans);
	}
	
	public static void main(String [] args) {
		Scanner cin = new Scanner(System.in);
		for(int i = 0; i< 3000; i++) num[i] = BigInteger.ZERO;
		int T = cin.nextInt();
		while(T-- > 0) {
			top = 0;
			n = cin.nextBigInteger();
			m = cin.nextBigInteger();
			if(n.equals(BigInteger.ZERO)) {
				System.out.println("0");
				continue;
			} else if(n.equals(BigInteger.ONE)) {
				System.out.println("1");
				continue;
			}
			BigInteger tn = n;
			while(n.compareTo(BigInteger.ZERO) > 0) {
				num[top++] = n.mod(BigInteger.valueOf(2));
				n = n.divide(BigInteger.valueOf(2));
			}
			for(int i = 0, j = top - 1; i < j; i++, j--) {
				BigInteger t = num[i];
				num[i] = num[j];
				num[j] = t;
			}
			n = tn;
			solve();
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值