HDOJ 3943 K-th Nya Number(数位DP)

题意:求区间(P , Q]中第K个恰含x个4和y个7的数。P,Q<2^63

分析:以前看到的数位DP的题都是求某个区间内满足给定条件的数的个数,看到这题我们一下可能没什么想法,也可能想到先求区间内的个数,然后二分答案,初看起来可以,但仔细想想就会发现有问题,因为即使知道(P , Q]内恰好有K个,你还是不知道第K个是哪个,所以二分貌似做不了。后来搜了下别人的解法,看过之后才恍然大悟,求解的过程非常巧妙,简而言之就是从高到低依次确定各个位的数字。不解释太多,看代码就明白了……

View Code
#include <stdio.h>

#include <string.h>

#define N 23

typedef __int64 LL;

int X,Y,digit[N];

LL P,Q,K,dp[N][N][N];

LL dfs(int pos,int x,int y,int f)

{

    if(pos==-1) return (x==X&&y==Y)?1:0;

    if(!f&&dp[pos][x][y]!=-1)   return dp[pos][x][y];

    LL ret=0;

    int max=f?digit[pos]:9;

    for(int i=0;i<=max;i++)

    {

        ret+=dfs(pos-1,x+(i==4),y+(i==7),f&&i==max);

    }

    if(!f)  dp[pos][x][y]=ret;

    return ret;

}

LL cal(LL x)

{

    int pos=0;

    while(x)

    {

        digit[pos++]=x%10;

        x/=10;

    }

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

}

void makeans(int pos,int x,int y,int f,LL k,LL &ans)

{

    if(pos==-1) return;

    LL ret=0;

    int i,max=f?digit[pos]:9;

    for(i=0;i<=max;i++)

    {

        if(ret+dfs(pos-1,x+(i==4),y+(i==7),f&&i==max)>=k)  break;

        ret+=dfs(pos-1,x+(i==4),y+(i==7),f&&i==max);

    }

    ans=ans*10+i;

    makeans(pos-1,x+(i==4),y+(i==7),f&&i==max,k-ret,ans);

}

void solve(LL x,LL k)

{

    k+=cal(P);

    int pos=0;

    while(x)

    {

        digit[pos++]=x%10;

        x/=10;

    }

    LL ans=0;

    makeans(pos-1,0,0,1,k,ans);

    printf("%I64d\n",ans);

}

int main()

{

    int t,n,ca=0;

    scanf("%d",&t);

    while(t--)

    {

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

        printf("Case #%d:\n",++ca);

        scanf("%I64d%I64d%d%d",&P,&Q,&X,&Y);

        scanf("%d",&n);

        while(n--)

        {

            scanf("%I64d",&K);

            if(cal(Q)-cal(P)<K) puts("Nya!");

            else    solve(Q,K);

        }

    }

    return 0;

}

你可能感兴趣的:(number)