SPOJ Sorted bit squence

来源:互联网 发布:2017年非农数据时间表 编辑:程序博客网 时间:2024/04/28 10:50

http://www.spoj.com/problems/SORTBIT/

题意 : 问你[l, r]在这段区间里面的数字二进制下数位上1的个数排序(按从小到大, 相同的话数值小的在前)后,第k个是谁。 -2^31 + 1 <= l <= r < 2 ^ 31 - 1,保证l, r同符号

思路 :二分 + 数位DP。 具体思路可以看下刘聪的《浅谈数位类统计问题》(第二题)

用深搜实现代码会显得简洁、

CODE :

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;typedef long long lld;const int maxn = 44;int dp[maxn][maxn];int bit[maxn];int dfs(int len, int num, int fp) {    if (!num)return 1;    if (!len)return num == 0;    if (!fp && dp[len][num] != -1)return dp[len][num];    int Max = (fp ? bit[len] : 1), res = 0;    for (int i = 0; i <= Max; i++) {        res += dfs(len - 1, num - (i == 1), fp && i == Max);    }    if (!fp)dp[len][num] = res;    return res;}int calc(lld x, int num) {    if (x < 0)return 0;    int len = 0;    while (x) {        bit[++len] = x % 2;        x >>= 1;    }    return dfs(len, num, 1);}int solve(lld l, lld r, int num) {    return calc(r, num) - calc(l - 1, num);}lld change(lld x) {    if (x >= 0)return (1LL << 32) - x;    else return (1LL << 32) + x;}lld work(lld L, lld R, int k) {    int ansk, ansc, c = 0;    while (k >= 1) {        ansk = k;        k -= solve(L, R, c);//not c        ansc = c++;    }    lld l = L, r = R;    while (r >= l) {        lld mid = r + l >> 1;        if (solve(L, mid, ansc) < ansk) {            l = mid + 1;        }else {            r = mid - 1;        }    }    return r + 1;}int main() {    int T;    memset(dp, -1, sizeof(dp));    scanf("%d", &T);    while (T--) {        lld L, R, k, res;        scanf("%lld%lld%lld", &L, &R, &k);        if (L >= 0) {            res = work(L, R, k);        }else {            res = -change(work(change(L), change(R), k));        }        printf("%lld\n", res);    }    return 0;}


0 0