题目链接:这里
题意:
Description

筑地市场是位于日本东京都中央区筑地的公营批发市场,为东京都政府设置的中央批发市场之一,亦是日本最大的鱼市场。其规模之大与知名度之广,不只是东京,更是日本首屈一指的批发市场。全球百分之五十的金枪鱼,从世界的各地被运往这里,在每天的清晨,进行着繁忙的拍卖,它们是寿司中最不可或缺的食材,如何能够买到上等的金枪鱼,成为了每家寿司店都关注的大事。

当地的鱼贩,会取出鱼腹的一小块进行观察,以辨别鱼品质的好坏…

我们将取出的小块可以看成是一个十进制数字串(没有前缀0),其中包含数字4或者7的数字串,被认为是好的。岛娘想知道所有的数字串中,数字串转为十进制数后排第 k 小(从1开始)的好字符串是多少,你可以帮助她吗?
Input

输入数据包含一行一个整数 k(k ≤ 1018)。
Output

输出数据包含一行,表示对应的十进制数字串。
Sample Input

19
Sample Output

54

解法:
二分之后数位DP去check就可以了,这道题就变成了给你x,问你小于等于x里面有多少个数,含有4或者7。

//Hihocoder 1301 二分+数位DP

#include <bits/stdc++.h>
using namespace std;
long long k;
long long dp[22][2];
int digit[22];
long long dfs(int l, int flag, bool jud){
    if(l == 0){
        return flag;
    }
    if(!jud && dp[l][flag] != -1) return dp[l][flag];
    int nex = jud ? digit[l] : 9;
    long long ans = 0;
    for(int i = 0; i <= nex; i++){
        ans += dfs(l-1, flag||(i==4)||(i==7), jud&&(i==nex));
    }
    if(!jud) dp[l][flag] = ans;
    return ans;
}
long long f(long long x){
    int num = 0;
    while(x){
        digit[++num] = x%10;
        x /= 10;
    }
    memset(dp, -1, sizeof(dp));
    return dfs(num, 0, 1);
}
int main(){
    scanf("%lld", &k);
    long long l = 1, r = 2e18, ans;
    while(l <= r){
        long long mid = (l+r)/2;
        if(f(mid)>=k) r=mid-1, ans=mid;
        else l = mid+1;
    }
    printf("%lld\n", ans);
    return 0;
}