CF431D Random Task
https://www.luogu.com.cn/problem/CF431D
首先
n
n
n关于个数是单调的,
n
n
n越大,个数越多
然后就可以二分+数位DP解决了
怎么证明是单调的呢?
考虑
[
n
+
1
,
2
n
]
和
[
n
+
2
,
2
n
+
2
]
[n+1,2n]和[n+2,2n+2]
[n+1,2n]和[n+2,2n+2]
中间
[
n
+
2
,
2
n
]
[n+2,2n]
[n+2,2n]是一样的,然后可以发现
n
+
1
n+1
n+1和
2
n
+
2
2n+2
2n+2 1的个数也是一样的
所以把
n
+
1
n+1
n+1后和
n
n
n做差只剩下一个
2
n
+
1
2n+1
2n+1,所以必然是单调的
code:
#include<bits/stdc++.h>
#define ll long long
#define N 85
using namespace std;
ll f[N][N][2], a[N];
ll m, k;
ll dfs(int len, int cnt, int lim) {
if(!len) return cnt == k;
ll &ret = f[len][cnt][lim];
if(ret != -1) return ret;
ret = 0;
int sx = lim? a[len] : 1;
for(int i = 0; i <= sx; i ++) ret += dfs(len - 1, cnt + i, lim && (i == sx));
return ret;
}
ll calc(ll x) {
memset(f, -1, sizeof f);
int len = 0;
while(x) a[++ len] = x & 1, x >>= 1;
return dfs(len, 0, 1);
}
int main() {
scanf("%lld%lld", &m, &k);
ll l = 0, r = 1e18;
while(l + 1 < r) {
ll mid = (l + r) >> 1;
if(calc(mid * 2) - calc(mid) >= m) r = mid;
else l = mid;
}
printf("%lld", r);
return 0;
}