POJ-3208 Apocalypse Someday (数位DP)

只要某数字的十进制表示中有三个6相邻,则该数字为魔鬼数,求第X小的魔鬼数\(X\le 5e7\)

这一类题目可以先用DP进行预处理,再基于拼凑思想,用“试填法"求出最终的答案

\(F[i,3]\)表示由 \(i\) 位数字构成的魔鬼数有多少个,\(F[i,j](0\le j\le 2)\) 表示由 \(i\) 位数字构成的,开头已经有连续 \(j\) 个6的非魔鬼数有多少个。(允许前导0的存在,想一想为什么)
转移方程

  1. \(F[i,0] = 9*(F[i-1,0] + F[i-1,1] + F[i-1,2])\)
  2. \(F[i,1] = F[i-1,0]\)
  3. \(F[i,2] = F[i-1,1]\)
  4. \(F[i,3] = F[i-1,2] + 10 * F[i-1,3]\)

然后一位一位的试填,要注意前面填过的数字结尾如果有 k 个6,通过后面拼接 3-k 个6也可以构成魔鬼数

#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
ll f[21][4];
int T,n,l;
void init(){
    f[0][0] = 1;
    for(int i=1;i<=20;i++){
        f[i][0] = 9*(f[i-1][0] + f[i-1][1] + f[i-1][2]);
        f[i][1] = f[i-1][0];
        f[i][2] = f[i-1][1];
        f[i][3] = f[i-1][2] + 10 * f[i-1][3];
    }
}
int main(){
    init();
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        //l为答案的长度
        for(l=3;f[l][3] < n;l++);
        //k表示填过的数字末尾有k个6
        for(int i=l,k=0;i;i--){
            for(int j=0;j<=9;j++){
                ll cnt = f[i-1][3];//后面预处理出的魔鬼数
                //找能够拼凑出来的魔鬼数
                if(j == 6 || k == 3){
                    if(k == 3){
                        for(int x = 0;x < 3;x++)
                            cnt += f[i-1][x];
                    }else{
                        for(int x = max(3-k-1, 0);x<3;x++){
                            cnt += f[i-1][x];
                        }
                    }
                }
                if(cnt < n) n -= cnt;
                else{
                    if(k < 3) j == 6 ? k ++ : k=0;
                    printf("%d",j);break;
                }
            }
        }
        cout<<endl;
    }
    return 0;
}

转载于:https://www.cnblogs.com/1625--H/p/11269361.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值