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