ZOJ- Numbers (貪心,枚舉,大數)
題面:
題意:
給定大整數\(n,m\),讓你選擇\(\mathit m\)個非負整數\(a_1, a_2, \dots, a_m\),使其滿足:
問你下式最小是多少?
思路:
首先\(O(log(n))\)算出最小的\(cnt,2^{cnt}>n\)。
然後我們貪心的來絕定答案的二進制信息中第\(\mathit i\)位取0還是1.
根據貪心思想,我們答案\(ans\)的第\(\mathit i\) 位若爲1時,那麼我們儘量讓\(a_j,j\in[1,m]\) 的第\(\mathit i\)位都1,這樣可以使其sum和更大,後面少一些位取1,答案可以更優。
那麼我們枚舉\(i\in[cnt,0]\),判斷當前是否滿足\(n\leq(2^i-1)\times m\),
若滿足,則爲了讓\(ans\)更小,該位不取1,讓後面位取1足以滿足條件。
否則,即:\(n>(2^i-1)\times m\)代表這\(\mathit m\)個數後面\(i-1\)位都取1時也無法達到sum和爲\(\mathit n\)。
那麼\(ans\)該位就必須取1.同時
代碼:
import java.math.*;
import java.util.Scanner;
public class Main {
public static void main(String[] args){
BigInteger zero=BigInteger.valueOf(0);
BigInteger one=BigInteger.valueOf(1);
BigInteger two=BigInteger.valueOf(2);
Scanner cin=new Scanner(System.in);
int t=cin.nextInt();
for(int icase=1;icase<=t;++icase)
{
BigInteger n=cin.nextBigInteger();
BigInteger m=cin.nextBigInteger();
BigInteger temp=n;
int cnt=0;
while(temp.compareTo(zero)>0)
{
cnt++;
temp=temp.divide(two);
}
cnt+=2;
BigInteger ans=zero;
BigInteger now;
BigInteger x;
for(int i=cnt;i>=0;--i)
{
now=two.pow(i).subtract(one);
if(n.compareTo(now.multiply(m))<=0)
continue;
now=now.add(one);
x=n.divide(now);
x=x.min(m);
ans=ans.add(now);
x=x.multiply(now);
n=n.subtract(x);
}
System.out.println(ans.toString());
}
}
}