b-number(dfs记忆化搜索 +数位 dp三维数组 )

A wqb-number, or B-number for short, is a non-negative integer whose decimal form contains the sub- string "13" and can be divided by 13. For example, 130 and 2613 are wqb-numbers, but 143 and 2639 are not. Your task is to calculate how many wqb-numbers from 1 to n for a given integer n.

Input

Process till EOF. In each line, there is one positive integer n(1 <= n <= 1000000000).

Output

Print each answer in a single line.

Sample Input

13
100
200
1000

Sample Output

1
1
2
2

题目大意: 统计1-n中所有含有13且能被13整除的数字的个数

思路 : dp[i][j][k]三位数组    分别表示数位    mod13 的模数  状态 

状态定义 : 因为递归从高位到低位  且含有13

                    当前面数不含‘13’且结尾不为1时  k = 0

                      不含‘13’’且结尾为1时  K = 1;

                      前面含有‘13‘’’时  k  = 2;

同时还要递归mod值    mod2 = mod*10+当前位数字

下面详解代码

 

        

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
int dp[20][13][3]; ///数位 模数  状态
int d[15];
///这一位下标为pos
///这一位之前的余数为mod 这一位之前的状态
///have= 0 前面末尾不是1 have  = 1 前面末尾是1   
/// have= 2  前面含有13  受不受限 limit
///即当前位为第pos位,前面是否有13,
///前面数字组成的数余数为k时的个数
int dfs( int pos, int mod , int have, int limit)
{
    if( pos <= 0 )
    {
        if( mod == 0 && have == 2 )   //当mod == 0 时说明该数可以整除13  have == 2说明含13
            return 1;                 //否则返回0 不符条件
        else
            return 0;
    }
    if( !limit && dp[pos][mod][have] != -1 )
     return dp[pos][mod][have];
    int ans = 0;
    int mod2, have2;
    int k = limit? d[pos]:9;
    for( int i = 0; i<=k; i++)
    {
         mod2 = (mod*10 + i)%13;  ///前面数字的余数*10 + 当前i即为当前mod
         have2 = have;
        if( have == 0 && i == 1 )  //have更新
            have2 =  1;
        if( have == 1 && i == 3 )
           have2 = 2;
        if( have == 1 && i != 1 && i != 3)
           have2 = 0;

        ans += dfs( pos-1, mod2, have2 , limit&&( i == k ));
    }
    if( !limit ) dp[pos][mod][have] = ans;
    return ans;  
}
int solve( int n )
{
    memset( d, 0, sizeof( d ));
    int cnt = 1;
    while( n > 0 )
    {
        d[cnt++] = n%10;
        n = n/10;
    }
    int ans = dfs( cnt-1, 0, 0, 1);
    return ans;
}
int main()
{
    int n;
    while(  scanf("%d", &n ) != EOF )
    {
        memset( dp, -1, sizeof( dp ));
        int ans = solve( n );
        printf("%d\n", ans );
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值