CodeForces 431D Random Task

洛谷传送门

CF 传送门

思路

引理:\(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;
}
posted @ 2022-07-02 18:09  zltzlt  阅读(35)  评论(0)    收藏  举报