cf 431D 二分+数位DP

来源:互联网 发布:炮哥捏脸数据 编辑:程序博客网 时间:2024/06/06 14:24

题意:给定 M, K,求一个数N,使得 N+1,N+2, .....,N*2 这些数中有M个数的二进制表示含有K个1

思路:

N的范围为1e18次方,然后又没有好的公式来求

所以可以试一下二分+数位DP判断

yy了下,要是mid求得的 个数小于M,则mid应该变大,反之则要变小。。。。

写了下真的可以,1A

AC代码如下:

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;int digit[100], tot;__int64 dp[100][100][2];__int64 M, K;__int64 DFS( int pos, int presum, bool st ){    if( pos < 0 ){        if( presum == K ){            return 1;        }else{            return 0;        }    }    if( !st && dp[pos][presum][st] != -1 ){        return dp[pos][presum][st];    }    __int64 ans = 0;    int endd = st ? digit[pos] : 1;    for( int i = 0; i <= endd; i++ ){        ans += DFS( pos - 1, presum + i, st && i == endd );    }    return dp[pos][presum][st] = ans;}__int64 solve( __int64 n ){    tot = 0;    while( n ){        digit[tot++] = n % 2;        n /= 2;    }    memset( dp, -1, sizeof( dp ) );    return DFS( tot - 1, 0, true );}int main(){    __int64 l, r, mid;    scanf( "%I64d%I64d", &M, &K );    l = 1;    r = 1e18;    while( l <= r ){        mid = ( l + r ) / 2;        __int64 t = solve( mid * 2 ) - solve( mid );        if( t == M ){            printf( "%I64d\n", mid );            return 0;        }else if( t < M ){            l = mid + 1;        }else{            r = mid - 1;        }    }    return 0;}


0 0
原创粉丝点击