题意:给出一个数字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 a1∣a2∣a3∣…∣am尽可能的小,输出最小值。
题解:如果让后来的或值最小的话,那么我们首先需要去掉最高位的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();
}
}
}