题目:http://acm.hdu.edu.cn/showproblem.php?pid=3943
给定X和Y的值,一个数字用十进制表示,对于数位4出现恰好X次,7恰好Y次的数字称为nya数。
然后给P和Q, 后面是一系列查询, 每个查询K就是在区间(P,Q]上找到第K个nya数,不存在则输出Nya!(= = 这是尖叫的意思么)
因为数字的范围比较大,又是跟数位有关,所以采取数位DP的算法。
dp[i][j][k],代表长度为i的数字中有j个4和k个7的个数。
先用递推的方法预处理出dp数组。
dp[i][j][k] += dp[i-1][j][k]*8,第i位不是4和7的情况;
dp[i][j+1][k] += dp[i-1][j][k],第i位为4;
dp[i][j][k+1] += dp[i-1][j][k],第i位为7;
然后读入p和q的时候先计算出对应的区间里nya数的个数tmp,然后读入k,如果k超过tmp就输出Nya!,否则二分出答案。
#include<cstdio>
#include<cstring>
#define LL long long
#define ull unsigned long long
ull dp[20][21][21];
void init(){
memset(dp,0,sizeof(dp));
dp[0][0][0]=1;
for(int i=1; i<20; i++){
for(int j=0; j<=20; j++){
for(int k=0; k<=20; k++) dp[i][j][k]+=dp[i-1][j][k]*8;
}
for(int j=0; j<20; j++){
for(int k=0; k<=20; k++){
dp[i][j+1][k]+=dp[i-1][j][k];
dp[i][k][j+1]+=dp[i-1][k][j];
}
}
}
}
int x, y;
ull query(ull a){
int buf[20];
int len=0;
while(a>0){
buf[len++]=(int)(a%10);
a/=10;
}
LL sum=0;
int j=x, k=y;
for(int i=len-1; i>=0; i--){
if(buf[i]<=4){
sum += (LL)buf[i]*dp[i][j][k];
if(buf[i]==4) j--;
}
else if(buf[i]<=7){
sum += (LL)(buf[i]-1)*dp[i][j][k];
if(j) sum += dp[i][j-1][k];
if(buf[i]==7) k--;
}
else{
sum += (LL)(buf[i]-2)*dp[i][j][k];
if(j) sum += dp[i][j-1][k];
if(k) sum += dp[i][j][k-1];
}
if(j<0 || k<0) break;
}
return sum;
}
int t, n;
ull p, q, k, tmp, cur;
int main(){
init();
scanf("%d", &t);
for(int ct=1; ct<=t; ct++){
printf("Case #%d:\n", ct);
scanf("%I64u %I64u %d %d", &p, &q, &x, &y);
tmp = query(q+1)-query(p+1);
scanf("%d", &n);
ull low, top, mid;
while(n--){
scanf("%I64u", &k);
if(k>tmp){
puts("Nya!");
continue;
}
low=p+1; top=q;
while(low<top){
mid = (low+top)/2;
cur = query(mid+1)-query(p+1);
if(cur<k) low=mid+1;
else top=mid;
}
printf("%I64u\n", low);
}
}
return 0;
}