sdut 2609 A-Number and B-Number

http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2609

数位DP 以前没怎么做过,自己憋了半天,还是看了标程,标程写的就是好呀。

相关注释见代码:

#include<iostream>

#include<cstdio>

#include<vector>

#include<stack>

#include<cstring>

#include<queue>

#include<algorithm>

#include<cmath>

#include<cstring>

#include<string>

#include<set>

#include<map>



#define ll long long

#define ull unsigned long long

using namespace std;

const int INF=0x3f3f3f3f;

ll dp[22][10][2];

int a[22];//把这一个数按位分解

ll dfs(int n,int x,int flag,int limit)

//这里表示的意思应该是 到第n位的时候,前面构成的数的余数是x

//flag代表是否有 7 limit代表是否限制大小

{

    if(n==-1)//边界

    return (flag||x==0);

    if(!limit&&dp[n][x][flag]!=-1)

    return dp[n][x][flag];

    ll ans=0;

    int up=(limit)?a[n]:9;

    for(int i=0;i<=up;++i)//枚举当前位的取值

    {

        ans+=dfs(n-1,(x*10+i)%7,(flag||i==7),(limit&&i==a[n]));

    }

    if(!limit)//当没有限制的时候 就是记忆化搜索 有限制就是普通的dfs

    dp[n][x][flag]=ans;

    return ans;

}

ll solve(ull x)

{

    int len=0;

    while(x)

    {

        a[len++]=x%10;

        x=x/10;

    }

    return dfs(len-1,0,0,1)-1;

}

ll fNum(ull x)

{

    ull tmp=solve(x);

    return tmp-solve(tmp);

}

int main()

{

    //freopen("data.in","r",stdin);

    memset(dp,-1,sizeof(dp));

    ll k;

    while(cin>>k)

    {

        ull l=1,r=(ull)(pow(2.0,63)-1.0);

        while(l<=r)//由于没有思路,根本没想到二分

        {

            ull mid=(l+r)>>1;

            if(fNum(mid)>=k)

            r=mid-1;

            else

            l=mid+1;

        }

        cout<<l<<endl;

    }

    return 0;

}

  

你可能感兴趣的:(number)