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;
}
posted @ 2021-10-10 22:08  lahlah  阅读(23)  评论(0编辑  收藏  举报