Hdu 2089 不要62(数位dp)

来源:互联网 发布:免费设计图标的软件 编辑:程序博客网 时间:2024/05/29 03:26

题目链接

不要62

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 21020    Accepted Submission(s): 7180


Problem Description
杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer)。
杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众。
不吉利的数字为所有含有4或62的号码。例如:
62315 73418 88914
都属于不吉利号码。但是,61152虽然含有6和2,但不是62连号,所以不属于不吉利数字之列。
你的任务是,对于每次给出的一个牌照区间号,推断出交管局今次又要实际上给多少辆新的士车上牌照了。
 

Input
输入的都是整数对n、m(0<n≤m<1000000),如果遇到都是0的整数对,则输入结束。
 

Output
对于每个整数对,输出一个不含有不吉利数字的统计个数,该数值占一行位置。
 

Sample Input
1 1000 0
 

Sample Output
80

题解:数位统计,具体可以看论文《浅谈数位类统计问题》。

两种方法的本质都是实现论文中按数位统计的方法。

方法一:记忆化搜索。

令数字最低位为0位,次低位为1位,依次递增

用dp[i][0]表示高于第i位的位没有出现不吉利数字,第i为到第0位任意填,总共有多少不吉利数字?

用dp[i][1]表示高于第i位的为没有出现不吉利数字,第i+1位为6,第i为到第0位任意填,总共有多少不吉利数字?

用dp[i][2]表示高于第i位的位已经出现了不吉利数字,第i位到第0位任意填,总共有多少不吉利数字?

转移就是:

dp[i][0]=0,如果第i位填4,dp[i][0]+=dp[i-1][2];如果第i位填6,dp[i][0]+=dp[i-1][1];其它情况,dp[i][0]+=dp[i-1][0]。

dp[i][1]=0,如果第i位填2或4,dp[i][1]+=dp[i-1][2];如果第i位填6,dp[i][1]+=dp[i-1][1];其它情况 dp[i][1]+=dp[i-1][0]

dp[i][2]=0,填任意数字dp[i][2]+=dp[i-1][2]。

用记忆化搜索的方式实现,在搜索过程中同时进行数位统计。

详情见代码:

#include<stdio.h>#include<iostream>#include<algorithm>#include<string.h>#include<math.h>typedef __int64 LL;using namespace std;int wei[30];LL l,r;LL dp[30][3];LL dfs(int id,int s,bool man){    if(id==-1)    {        if(s==2)            return 1;        return 0;    }    if(!man&&dp[id][s]!=-1)    {        return dp[id][s];    }    int end=man?wei[id]:9;    int i;    LL re=0;    for(i=0;i<=end;i++)    {        if(s==0)        {            if(i==6)            {                re+=dfs(id-1,1,man&&i==end);            }            else if(i==4)                re+=dfs(id-1,2,man&&i==end);            else                re+=dfs(id-1,0,man&&i==end);        }        if(s==1)        {            if(i==2)                re+=dfs(id-1,2,man&&i==end);            else if(i==6)                re+=dfs(id-1,1,man&&i==end);            else if(i==4)                re+=dfs(id-1,2,man&&i==end);            else                re+=dfs(id-1,0,man&&i==end);        }        if(s==2)            re+=dfs(id-1,2,man&&i==end);    }    if(!man)        return dp[id][s]=re;    return re;}LL solve(LL x){    int ix=0;    while(x)    {        wei[ix++]=x%10;        x/=10;    }    return dfs(ix-1,0,true);}int main(){    memset(dp,-1,sizeof(dp));    while(scanf("%I64d%I64d",&l,&r)&&l+r)    {        l--;        LL ans=r-l-(solve(r)-solve(l));        printf("%I64d\n",ans);    }    return 0;}

方法二:递推。

用dp[i][j][0,1] 表示第i位填j,i-1到0位任意填,0表示所有数字的个数,1表示包含不吉利数字的个数。

递推预处理出dp数组,直接采用论文中的统计方法统计即可。

详情见代码:

#include<stdio.h>#include<iostream>#include<algorithm>#include<string.h>#include<math.h>typedef __int64 LL;using namespace std;int wei[30];LL l,r;LL dp[30][10][2];void init(){    int i,j,k;    for(i=0;i<=9;i++)    {        dp[0][i][0]=1;        dp[0][i][1]=0;        if(i==4)            dp[0][i][1]=1;    }    for(i=1;i<=18;i++)    {        for(j=0;j<=9;j++)        {            dp[i][j][0]=0;            dp[i][j][1]=0;            for(k=0;k<=9;k++)            {                dp[i][j][0]+=dp[i-1][k][0];                if(j==4)                    dp[i][j][1]+=dp[i-1][k][0];                else if(j==6&&k==2)                    dp[i][j][1]+=dp[i-1][k][0];                else                    dp[i][j][1]+=dp[i-1][k][1];            }        }    }}LL solve(LL x){    int ix=0;    while(x)    {        wei[ix++]=x%10;        x/=10;    }    wei[ix]=0;    LL re=0;    int s=0;    int i,j;    for(i=ix-1;i>=0;i--)    {        for(j=0;j<wei[i];j++)        {            if(s==0)            {                if(wei[i+1]==6&&j==2)                {                    re+=dp[i][j][0];                }                else if(j==4)                    re+=dp[i][j][0];                else                    re+=dp[i][j][1];            }            else            {                re+=dp[i][j][0];            }        }        if(s==0)        {            if(wei[i]==4)                s=1;            if(wei[i+1]==6&&wei[i]==2)                s=1;        }    }    if(s==1)        re++;    return re;}int main(){    init();    while(scanf("%I64d%I64d",&l,&r)&&l+r)    {        l--;        LL ans=r-l-(solve(r)-solve(l));        printf("%I64d\n",ans);    }    return 0;}



0 0
原创粉丝点击