hihocoder #1301 : 筑地市场 数位dp+二分

题目链接:

http://hihocoder.com/problemset/problem/1301?sid=804672

题解:

二分答案,每次判断用数位dp做。

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

typedef long long LL;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;

//dp[x][0]表示高位还没有出现4,7。
//dp[x][1]表示高位已经出现4,7了。
LL dp[22][2];
bool vis[22][2];
LL k;

int num[22];
//z表示高位是不是刚好在最大的边界上。
LL dfs(int cur, int y, int z) {
    if (cur == -1 && y) return 1;
    if (cur == -1) return 0;
    if (vis[cur][y] && !z) return dp[cur][y];
    int e = z ? num[cur] : 9;
    LL res = 0;
    for (int i = 0; i <= e; i++) {
        res += dfs(cur - 1, y || i == 4 || i == 7, z && (i == e));
    }
    if (!z) {
        dp[cur][y] = res;
        vis[cur][y] = 1;
    }
    return res;
}

bool ok(LL x) {
    int tot = 0;
    while (x) {
        num[tot++] = x % 10;
        x /= 10;
    }
    memset(dp, 0, sizeof(dp));
    memset(vis, 0, sizeof(vis));
    LL res = dfs(tot - 1, 0, 1);
    return res<k;
}

int main() {
    while (scanf("%lld", &k) == 1) {
        LL l = 1, r = INFLL;
        //printf("r:%lld\n", r);
        while (l + 1 < r) {
            LL mid = l + (r - l) / 2;
            if (ok(mid)) l = mid;
            else r = mid;
        }
        printf("%lld\n", l + 1);
    }
    return 0;
}

 

posted @ 2016-06-09 01:30  fenicnn  阅读(174)  评论(0编辑  收藏  举报