转载请注明出处,谢谢 http://blog.youkuaiyun.com/ACM_cxlove?viewmode=contents by---cxlove
HDU 3943 K-th Nya Number
http://acm.hdu.edu.cn/showproblem.php?pid=3943
用X个4和Y个7的数为规定的数,然后就是区间统计。
先预处理好dp[i][j][k]表示I位的数中有j个4和k个7的数量。
之后就可以通过高位开始枚举,求出区间内有多少个规定的数,如果询问大于总数,则输出"Nya!";
之后是怎么找到第K大数。
首先可以确定出位数,dp[i][x][y]表示i位时的满足数,那么大于dp[len-1][x][y]而小于dp[len][x][y],len表示目标位数。
确定了位数之后,依旧从高位开始。比如说高位首先是0,而dp[len-1][x][y]小于k,说明0开头的目标说小于所求,所以往后继续找,记得要把之前的减掉。
还得注意一些细节,出现了4和7的情况。
貌似有题解说的是二分查找,没有过多的了解。
另外坑的是 这里的区间是左开右闭。
#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define N 100005
#define inf 1<<29
#define MOD 9973
#define LL long long
#define eps 1e-7
#define zero(a) fabs(a)<eps
#define equal(a,b) zero(a-b)
using namespace std;
LL dp[25][25][25];
//dp[i][j][k]表示i位的数,有j个4,k个7的数量
LL l,r;
int x,y;
void Init(){
memset(dp,0,sizeof(dp));
dp[0][0][0]=1;
for(int i=1;i<21;i++){
for(int j=0;j<i;j++)
for(int k=0;k<i;k++)
if(j+k<i){
dp[i][j][k+1]+=dp[i-1][j][k];
dp[i][j+1][k]+=dp[i-1][j][k];
dp[i][j][k]+=dp[i-1][j][k]*8;
//在高位加上除了4、7以外的8个数字
}
}
}
LL get_count(LL n){
int bit[25],len=0;
while(n){
bit[++len]=n%10;
n/=10;
}
LL ans=0;
int cx=x,cy=y;
for(int i=len;i;i--){
//从高位开始枚举
for(int j=0;j<bit[i];j++)
if(j==4){
if(cx)
ans+=dp[i-1][cx-1][cy];
}
else if(j==7){
if(cy)
ans+=dp[i-1][cx][cy-1];
}
else
ans+=dp[i-1][cx][cy];
if(bit[i]==4)
cx--;
if(bit[i]==7)
cy--;
//如果高位出现的4、7数量已经超过要求,则退出
if(cx<0||cy<0)
break;
}
return ans;
}
LL slove(LL k){
int len=1;
while(1){
//找到目标数的长度
if(dp[len-1][x][y]<k&&dp[len][x][y]>=k)
break;
len++;
}
LL ret=0;
int cx=x,cy=y;
for(int i=len;i;i--){
//从高位开始从小枚举
for(int j=0;j<10;j++){
int tx=cx,ty=cy;
if(j==4){
tx--;
if(tx<0)
continue;
}
if(j==7){
ty--;
if(ty<0)
continue;
}
if(dp[i-1][tx][ty]>=k){
ret=ret*10+j;
cx=tx;
cy=ty;
break;
}
k-=dp[i-1][tx][ty];
}
}
return ret;
}
int main(){
int t,cas=0;
scanf("%d",&t);
Init();
while(t--){
scanf("%I64d%I64d%d%d",&l,&r,&x,&y);
LL a=get_count(r+1);
LL b=get_count(l+1); //注意是左开区间,悲剧了好久
int q;
scanf("%d",&q);
printf("Case #%d:\n",++cas);
while(q--){
LL k;
scanf("%I64d",&k);
if(k>a-b)
puts("Nya!");
else
printf("%I64d\n",slove(k+b));
}
}
return 0;
}