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());
}
}
}
本博客为本人原创,如需转载,请必须声明博客的源地址。
本人博客地址为:www.cnblogs.com/qieqiemin/
希望所写的文章对您有帮助。