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());
		}

	}

}

posted @ 2020-11-03 00:48  茄子Min  阅读(70)  评论(0编辑  收藏  举报