CodeForces 431D Random Task
思路
引理:设 \(f(x)\) 为 \(x+1 \sim 2x\) 中二进制表示恰好含有 \(k\) 个 \(1\) 的数的个数,则对于任意 \(x\ (x \ge 1)\),都有 \(f(x) \le f(x+1)\)。
证明:\(f(x)\) 表示 \(x+1 \sim 2x\) 中二进制表示恰好含有 \(k\) 个 \(1\) 的数的个数,而 \(f(x+1)\) 表示 \(x+2 \sim 2x+2\) 中二进制表示恰好含有 \(k\) 个 \(1\) 的数的个数。二者作差,得到 \(f(x+1) - f(x)\) 表示 \(2x+2,2x+1\) 中二进制表示恰好含有 \(k\) 个 \(1\) 的数的个数减去 \(x+1\) 二进制表示是否恰好含有 \(k\) 个 \(1\)。发现 \(2x+2\) 相当于是 \(x+1\) 在二进制下右移一位得到的,所以它们的含有 \(1\) 的个数必然相等,所以若 \(x+1\)(不)符合条件,则 \(2x+2\) 也(不)符合条件。此时还多一个 \(2x+1\),显然若 \(2x+1\) 恰好含有 \(k\) 个 \(1\) 则 \(f(x+1) = f(x)+1\),否则 \(f(x+1) = f(x)\)。综上,\(f(x) \le f(x+1)\)。
有了单调性,就可以直接二分答案,然后数位 dp(记搜)即可。dp 数组要多一维,表示当前含有 \(1\) 的数量。
代码
code
/*
p_b_p_b txdy
AThousandMoon txdy
AThousandSuns txdy
hxy txdy
*/
#include <bits/stdc++.h>
#define pb push_back
#define fst first
#define scd second
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pii;
ll f[65][2][2][65], a[65], m, K;
ll dfs(int pos, bool limit, bool lead, int cnt) {
if (!pos) {
return cnt == K;
}
if (f[pos][limit][lead][cnt] != -1) {
return f[pos][limit][lead][cnt];
}
ll ans = 0, up = (limit ? a[pos] : 1);
for (int i = 0; i <= up; ++i) {
ans += dfs(pos - 1, limit && (i == up), lead && (!i), cnt + (i == 1));
}
return f[pos][limit][lead][cnt] = ans;
}
ll solve(ll x) {
memset(f, -1, sizeof(f));
int tot = 0;
while (x) {
a[++tot] = (x & 1);
x >>= 1;
}
return dfs(tot, 1, 1, 0);
}
void solve() {
scanf("%lld%lld", &m, &K);
ll l = 1, r = 1e18, ans = -1;
while (l <= r) {
ll mid = (l + r) >> 1;
if (solve(mid * 2) - solve(mid) >= m) {
ans = mid;
r = mid - 1;
} else {
l = mid + 1;
}
}
printf("%lld\n", ans);
}
int main() {
int T = 1;
// scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}

浙公网安备 33010602011771号