您的位置:首页 > 其它

HDU 3943 —— K-th Nya Number(数位DP,二分答案)

2014-03-04 22:14 429 查看
题目: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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: