1. 程式人生 > >Numbers ZOJ - 3987[思維暴力]

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

    詢問如何讓 a 1 a
    2 a 3 a m a_1|a_2|a_3|\dots|a_m
    儘可能的小,輸出最小值。

題解:如果讓後來的或值最小的話,那麼我們首先需要去掉最高位的1(二進位制下),然後我們的工作就成為了從高到低判斷某一位是否放1,我們在判斷某一位的時候我們需要判斷他後面的數字如果全部為1的時候是否比N還要大,如果可以的話,這一位可以不放1,否則的一定要放1,該位放1,那麼相應的其他(m-1)個數字也要放1(讓N儘量的小),然後統計答案即可。(大數不可少


收穫:轉化為一個較為容易實現的問題,如判斷某位是否要放1


a c   c o d e : 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();
		}
	}
}