ZOJ- Numbers (貪心,枚舉,大數)

ZOJ- Numbers (貪心,枚舉,大數)

題面:

題意:

給定大整數\(n,m\),讓你選擇\(\mathit m\)個非負整數\(a_1, a_2, \dots, a_m\),使其滿足:

\[n=a_1 + a_2 + \dots + a_m \]

問你下式最小是多少?

\[a_1 \text{ OR } a_2 \text{ OR } \dots \text{ OR } 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.同時

\[n-=min( floor(\frac{n}{2^i-1}),m)*(2^i-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());
		}

	}

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章