hihoCoder 1301 筑地市场 数位dp加二分答案

#1301 : 筑地市场

时间限制: 7000ms
单点时限: 1000ms
内存限制: 256MB

描述

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

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

hihoCoder 1301 筑地市场 数位dp加二分答案_第1张图片

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

输入

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

输出

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

样例输入
19
样例输出
54
Emacs Normal Vim


是岛娘出的题么

简单数位dp然后二分答案就好啦 //一开始开的1e18wa了后来改1e19就ac了

ACcode;

#include <cstdio>
#include <cstring>
#include <string>
#define ll long long
ll dp[20][2][2];
ll data[20];
ll dfs(int len,int is_4,int is_7,int limit){
    if(!len)return (is_4||is_7)?1ll:0ll;
    if(!limit&&dp[len][is_4][is_7]!=-1ll)return dp[len][is_4][is_7];
    int ed=limit?data[len]:9;
    ll ans=0;
    for(int i=0;i<=ed;++i)
        ans+=dfs(len-1,is_4||i==4,is_7||i==7,limit&&i==ed);
    return limit?ans:dp[len][is_4][is_7]=ans;
}
ll fun(ll a){
    int len=0;
    while(a){
        data[++len]=a%10;
        a/=10;
    }
    return dfs(len,0,0,1);
}
void doit(ll a){
    ll l=1,r=1e19+2ll;
    while(l<r){
        ll mid=(l+r)>>1;
        ll ans=fun(mid);
       // printf("mid   %lld   ans  %lld\n",mid,ans);
        if(ans==a){
            while(ans==fun(mid))mid--;
            printf("%lld\n",mid+1);
            return ;
        }
        if(ans<a)l=mid;
        if(ans>a)r=mid;
    }
}
void init(){
    ll ans=1e19+2ll;
    int len=0;
    while(ans){
        data[++len]=ans%10;
        ans/=10;
    }
    dfs(len,0,0,1);
}
int main(){
    ll a;memset(dp,-1,sizeof(dp));
    init();
    while(~scanf("%lld",&a))doit(a);
}


你可能感兴趣的:(C++,dp,ACM)