参考自:https://blog.csdn.net/u013534123/article/details/78484494
题意:
给出两个数字n,m,把n分成m份,使得以下最小
思路:
或运算只有0|0=0,如果这一位有一个1,那么结果中这一位一定是1,所以我们要尽可能把1集中在几个位上(以二进制看结果)
(二进制)主要的思想是把高位设置成1,这样可以分担大部分数值
用 i-1 位全部为1的二进制数t × m 与n进行判断
如果n大,说明n可以分成 pow(2,i)*m+x,x为不确定数字,这样说明把m个数字第i为设置为1
如果n小,说明分不出来,继续使i变小判断
代码:
import java.util.*;
import java.io.*;
import java.math.*;
public class Main {
public static BigInteger two = BigInteger.valueOf(2);
public static BigInteger p[] = new BigInteger[5000];
public static void init() //预处理二进制下每一位都为1的值
{
p[1] = BigInteger.ONE;
p[0] = BigInteger.ZERO;
for (int i = 2; i < 5000; i++)
p[i] = p[i - 1].multiply(two);
for (int i = 2; i < 5000; i++)
p[i] = p[i].add(p[i - 1]); //p[i]不仅是二进制i位为1,还记录了加和
}
public static void main(String[] args) {
init();
Scanner cin = new Scanner(System.in);
int T = cin.nextInt();
for (int ca = 1; ca <= T; ca++) {
BigInteger ans = BigInteger.ZERO;
BigInteger a = cin.nextBigInteger();
BigInteger b = cin.nextBigInteger();
int up = 0;
for (int i = 0; i < 5000; i++) //首先找到最高位
if (p[i].compareTo(a) > 0) { //找到第一个比a大的数
up = i;
break;
}
for (int i = up; i >= 1; i--) {
ans = ans.multiply(two); //还原二进制为十进制
if (a.compareTo(p[i - 1].multiply(b)) <= 0) continue; //若后面可以大于n剩余的量,那么这一位放0
BigInteger now = p[i].subtract(p[i - 1]); //否则就只能放1,而且要让n尽量减去更多,剩下更少
BigInteger k = a.divide(now);
ans = ans.add(BigInteger.ONE);
if (k.compareTo(b) > 0) a = a.subtract(now.multiply(b));
else a = a.subtract(now.multiply(k));
}
System.out.println(ans);
}
}
}