POJ3208-Apocalypse Someday【数位dp】

正题

题目链接:http://poj.org/problem?id=3208


题目大意

求第X个有3个连续的6的数。


解题思路

fi,j(j<3) f i , j ( j < 3 ) 表示i位,已经有j个6的方案总数。然后 fi,3 f i , 3 表示i位的魔鬼数的总数。
然后动态转移方程。

fi,0=9(fi1,0+fi1,1+fi1,2) f i , 0 = 9 ∗ ( f i − 1 , 0 + f i − 1 , 1 + f i − 1 , 2 )

只要一个不是6的数就能间断他们
fi,1=fi1,0 f i , 1 = f i − 1 , 0

fi,2=fi1,1 f i , 2 = f i − 1 , 1

加一个6
fi,3=fi1,2+10fi1,3 f i , 3 = f i − 1 , 2 + 10 ∗ f i − 1 , 3

上一位加任意一个数或两个六的情况下加一个6。
然后试填就好了


code

#include<cstdio>
#include<algorithm>
using namespace std;
long long f[21][4];
int t,n,m;
int main()
{
    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];
    }//dp
    scanf("%d",&t);
    for(int ti=1;ti<=t;ti++)
    {
        scanf("%d",&n);
        for(m=3;f[m][3]<n;m++);//判断位数
        for(int i=m,k=0;i;i--)//枚举填入位数
        {
            for(int j=0;j<=9;j++)//填入j
            {
                long long cnt=f[i-1][3];//判断位数
                if(j==6||k==3)
                  for(int l=max(3-k-(j==6),0);l<3;l++)
                    cnt+=f[i-1][l];//特判统计
                if(cnt<n)n-=cnt;//超过这个位数
                else
                {
                  if(k<3)//位数不足3时特判特殊判断
                  {
                    k+=(j==6);
                    k*=(j==6);
                  }
                  printf("%d",j);//输出
                  break;//填完了
                }   
            }
        }
        printf("\n");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值