题目链接:传送门
参考文章
题目:
输入一个n,m求出 序列ai,满足Σai = n,最终使序列ai序列或值最小。
思路:
1、考虑将n均分为m个数字
2、考虑特殊情况n = 314,m = 10;
此时如果均分为32,31,但是32|31 = 63,因为从n/m到n/m+1的二进制数字进位了,所以这样分并不能使最终或值最小。
可以对每次的除数x = n/m+1,然后判断x二进制数字是不是等于2^k;
(1)如果x == 2^k,分配2 ^ k数字,防止进位导致过大;
eg:给314分配(314/32)个32,更新n = 314 - (314/32)* 32 = 26;ans += 32;
(2)如果x != 2^k,考虑除了二进制最后一位一不分配其他都分配即分配( x - lowbit(x) ).
eg:n = 26,m = 10时,算出x = 3;( x - lowbit(x) ) = 2,所以给每个数字分配2,剩余n = 26 - 10*2 = 6,同时更新答案ans += 2;
这样分配可以让每次分配尽量大的数字,但是最终的结果能达到最小。(大数用Java实现更方便)
代码:
import java.util.*;
import java.math.*;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner input = new Scanner(System.in);
BigInteger zero = new BigInteger("0");
BigInteger one = new BigInteger("1");
BigInteger two = new BigInteger("2");
int T = input.nextInt();
for(int i=0;i<T;i++) {
BigInteger a = input.nextBigInteger();
BigInteger b = input.nextBigInteger();
if(a.mod(b).equals(zero) == true) {
System.out.println(a.divide(b));
continue;
}
BigInteger ans = zero;
while(a.compareTo(zero) == 1) {
BigInteger tp = a.divide(b).add(one);
BigInteger left = lowbit(tp);
if(left.equals(tp) == true) {
a = a.subtract(a.divide(tp).multiply(tp));
ans = ans.add(tp);
}
else {
tp = tp.subtract(left);
a = a.subtract(b.multiply(tp));
ans = ans.add(tp);
}
}
System.out.println(ans);
}
}
public static BigInteger lowbit(BigInteger x) {
return x.and(x.multiply(new BigInteger("-1")));
}
}