码迷,mamicode.com
首页 > 其他好文 > 详细

数位DP入门

时间:2019-02-02 01:02:33      阅读:265      评论:0      收藏:0      [点我收藏+]

标签:author   turn   表示   司机   代码   交通   统计   问题   结束   

以HDU2089为例:

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 100 0 0
 

 

Sample Output
80
 

 

Author
qianneng

 

即求从n-m中数位不含62和4的个数。

设dp[i][j]表示长度为i,最高位是j的数位中符合条件的数

显然 若j=4,dp[i][j]=0.若j=6,则dp[i][j]=sum(dp[i-1][k], k!=2,k>=0,k<9),否则dp[i][j]=sum(dp[i][k],k>=0,k<9)

定义函数 count(x),表示严格小于x的数,满足条件的有多少个。

则问题转化为求count(m+1)-count(n)。

如何求count?

考虑x的每一位,则分为两个部分,严格小于第i位的和加上第i位相等,比较第i-1位。

比如 556 。就加上dp[3][1],dp[3][2],dp[3][3],dp[3][4],这是严格小于5的,然后等于5的部分,加上dp[2][1],dp[2][2],dp[2][3],dp[2][4],最后加上dp[1][1],dp[1][2],dp[1][3],dp[1][4],dp[1][5]。

但有种特殊情况 如456. 先加上dp[3][1],dp[3][2],dp[3][3],这严格小于4的部分,之后到了等于4的部分,这是不满足条件的,所以不能算。直接break掉,62同理

#include <bits/stdc++.h>
#define maxn 25
using namespace std;
int dp[maxn][maxn];
void init()
{
    dp[0][0]=1;
    for(int i=1;i<=9;++i)
    {
        for(int j=0;j<=9;++j)
        {
            if(j==4) dp[i][j]=0;
            else if(j==6)
            {
                for(int k=0;k<=9;++k)
                {
                    if(k!=2) dp[i][j]+=dp[i-1][k];
                }
            }
            else
            {
                for(int k=0;k<=9;++k)
                {
                     dp[i][j]+=dp[i-1][k];
                }
            }
        }
    }
}
int a[10];
int count(int x)
{
    memset(a,0, sizeof(a));
    int cnt=0;
    while(x>0)
    {
        a[++cnt]=x%10;
        x/=10;
    }
    int res=0;
    for(int i=cnt;i>=1;--i)
    {
        for(int j=0;j<a[i];++j)
        {
            if(j!=4&&!(a[i+1]==6&&j==2)) res+=dp[i][j];
        }
        if(a[i]==4) break;
        if(a[i+1]==6&&a[i]==2) break;
    }
    return res;
}
int main()
{
    int n,m,k;
    init();
    //cout<<dp[2][6]<<endl;
    while(~scanf("%d%d",&n,&m)&&n&&m)
    {
        printf("%d\n",count(m+1)-count(n));
    }
    return 0;
}

  

代码如下:

数位DP入门

标签:author   turn   表示   司机   代码   交通   统计   问题   结束   

原文地址:https://www.cnblogs.com/zyf3855923/p/10347401.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!