题目
题意
求任意 n n n,满足 n + 1 n+1 n+1 到 2 n 2n 2n 中有 m m m 个数二进制位有 k k k 个 1 1 1
题解
首先,有 k k k 个 1 1 1 的数字个数,对于 n n n 是单调的:考虑一开始为 n n n,则序列为 n + 1 , n + 2 + . . . + 2 n n+1,n+2+...+2n n+1,n+2+...+2n,若为 n + 1 n+1 n+1,则为 n + 2 , n + 3 + . . . + 2 n + 2 n+2,n+3+...+2n+2 n+2,n+3+...+2n+2。变化为:
- 少了 n + 1 n+1 n+1
- 多了 2 n + 1 、 2 n + 2 2n+1、2n+2 2n+1、2n+2
而 2 n + 2 2n+2 2n+2 与 n + 1 n+1 n+1, 1 1 1 的个数相同,那么只需要看多出来的 2 n + 1 2n+1 2n+1。而无论 2 n + 1 2n+1 2n+1 是否有 k k k 个 1 1 1,答案至少是不降的。
因此,我们选择二分这个 n n n。
对于一个 n n n,如何得到它的序列里有多少个满足条件的数呢?这里直接用组合数算就行了,详见代码(这句话似乎在Fart)。
LL C[MAXM][MAXM];
inline Prepare()
{
C[0][0] = 1;
for (Int i = 1; i <= 64; ++ i)
{
C[i][0] = 1;
for (Int j = 1; j <= i; ++ j)
C[i][j] = C[i - 1][j] + C[i - 1][j - 1];
}
}
LL m, k;
inline LL Solve(LL x)
{
LL Res = 0, Meet = 0;
for (Int i = 63; i >= 0; -- i)
if (x & (1ll << i))
{
if (Meet <= k)
Res += C[i][k - Meet];
Meet ++;
}
return Res;
}
int main()
{
Prepare();
read( m ); read( k );
LL l = 1, r = 1000000000000000000ll;
while (1 + 1 == 2)
{
// printf("%lld %lld\n", l, r);
LL Mid = (l + r) / 2;
LL Get = Solve(2 * Mid) - Solve( Mid );
// printf("%lld %lld\n", Solve(2 * Mid), Solve( Mid ));
if (Get > m)
r = Mid - 1;
else if (Get == m)
return ! printf("%lld", Mid);
else l = Mid + 1;
}
return 0;
}