HDOJ 3943 Kth 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;
}
原文地址:https://www.cnblogs.com/algorithms/p/2685335.html