【数位DP】HDU3555[Bomb]题解

来源:互联网 发布:it专业大学排名 编辑:程序博客网 时间:2024/05/18 08:07

题目概述

[1,n] 中存在一个子段是 49 的数的个数。

解题报告

定义 f[i][j][0/1] 表示前 i 位第 i 位为 j 是否出现 49 的方案数。

然后直接做就行了……不过由于只需要管 49 所以并不需要存 j ,可以直接定义 f[i][0/1/2] 表示出现 49 /没出现 49 末尾是 9 /没出现 49 末尾不是 9 ,更加简单……

示例程序

我程序有毒,读者老爷请凑合着看……QAQ

#include<cstdio>#include<cstring>using namespace std;typedef long long LL;const int maxn=20;int te,a[maxn+5];LL n,sum[maxn+5],f[maxn+5][10][2];void Make(){    for (int t=2;t<=maxn;t++)    {        memset(f,0,sizeof(f));for (int j=1;j<10;j++) f[1][j][0]=1;        for (int i=2;i<=t;i++)        for (int j=0;j<10;j++)        for (int k=0;k<10;k++)        for (int t=0;t<2;t++)            f[i][j][t||k==4&&j==9]+=f[i-1][k][t];        sum[t]=sum[t-1];for (int j=0;j<10;j++) sum[t]+=f[t][j][1];    }}#define p(x) (a[0]-(x)+1)inline LL DP(LL n){    a[0]=0;do a[++a[0]]=n%10,n/=10; while(n);    if (a[0]==1) return 0;LL ans=sum[a[0]-1];    memset(f,0,sizeof(f));for (int j=1;j<a[p(1)];j++) f[1][j][0]=1;    for (int i=2;i<=a[0];i++)    for (int j=0;j<10;j++)    for (int k=0;k<10;k++)    for (int t=0;t<2;t++)        f[i][j][t||k==4&&j==9]+=f[i-1][k][t];    for (int j=0;j<10;j++) ans+=f[a[0]][j][1];    for (int t=1,fst=0;t<a[0];t++)    {        memset(f,0,sizeof(f));if (t>1) fst|=a[p(t-1)]==4&&a[p(t)]==9;        for (int j=0;j<a[p(t+1)];j++) f[t+1][j][fst||a[p(t)]==4&&j==9]=1;        for (int i=t+2;i<=a[0];i++)        for (int j=0;j<10;j++)        for (int k=0;k<10;k++)        for (int t=0;t<2;t++)            f[i][j][t||k==4&&j==9]+=f[i-1][k][t];        for (int j=0;j<10;j++) ans+=f[a[0]][j][1];    }    for (int i=2;i<=a[0];i++) if (a[p(i-1)]==4&&a[p(i)]==9) return ans+1;    return ans;}int main(){    freopen("program.in","r",stdin);    freopen("program.out","w",stdout);    for (Make(),scanf("%d",&te);te;te--) scanf("%lld",&n),printf("%lld\n",DP(n));    return 0;}
原创粉丝点击