HDU 3652 B-number

1 篇文章 0 订阅

B-number

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1813    Accepted Submission(s): 990


Problem Description
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
 

Author
wqb0039
 

Source
 

Recommend
lcy   |   We have carefully selected several similar problems for you:   3655  3654  3653  3659  3658 
 
题意:有一个数N, 找出[1, N] 中的整数, 存在13, 并且能整除13的个数。

思路: 数位DP  在HDU 3555 基础上, 加多一个状态。就是mod.

不同于网上的 记忆化搜索,我比较喜欢用迭代。 思路比较清晰。

附2000以内的数,  13, 130, 1131, 1300, 1313, 1326, 1339, 1352, 1365, 1378, 1391。 11个。

原理。


所以i = 4的时候, 是衔接  0~5  和 (0~999  就是预处理dp[3][?][?]里)
所以i = 3的时候, 是衔接  0~1  和 (0~99  就是预处理dp[2][?][?]里)
所以i = 2的时候, 是衔接  0~2  和 (0~9  就是预处理dp[1][?][?]里)
所以i = 1的时候, 是衔接  0~8  和 (-  就是预处理dp[0][?][?]里)

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int V = 10;
const int mod= 13;
int dp[V][mod][3], a;
//dp[i][j][0~2], 长度为i的所有整数中,模13余j的(0: 无13, 1:无13,且最高位为3, 2:有13)的个数。
int MOD[V]; //10^(V - 1) % 13
void init() {
    //初始化MOD
    MOD[1] = 1;
    for(int i = 2; i < V; ++i)
        MOD[i] = (MOD[i - 1] * 10) % mod;
    // 初始化长度为0的情况。存在一个长度为0,余13为0的,不存在13的个数。
    dp[0][0][0] = 1;
    // 初始化长度为1的情况。 只有10个数字。
    for(int j = 0; j <= 9; ++j)
        dp[1][j][0] = 1;
    dp[1][3][1] = 1;
    // 往后转移状态
    for(int i = 1; i < V - 1; ++i)//长度为i
        for(int j = 0; j < mod; ++j) // 模
            for(int k = 0; k <= 9; ++k) { //i + 1位为k.
                int temp_j = (j + k * MOD[i + 1]) % mod; //算出对应的模。
                //有多少就转移多少
                dp[i + 1][temp_j][0] += dp[i][j][0]; 
                dp[i + 1][temp_j][2] += dp[i][j][2]; 
                
                if(k == 1) { //如果i + 1位加一,无13的情况, 要去掉第i位是3的, 并且有13的情况要加上第i位是3的。
                    dp[i + 1][temp_j][0] -= dp[i][j][1];
                    dp[i + 1][temp_j][2] += dp[i][j][1];
                }
                if(k == 3) //如果i + 1 位加3, 则加上无13的数量。
                    dp[i + 1][temp_j][1] += dp[i][j][0];
            }
}
int f(int a) {
    int bit[V], top = 0;
    int ans = 0;
    while(a) {
        bit[++top] = a % 10;
        a /= 10;
    }
    bool flag = false;
    int pre = 0; //记录之前出现的数字。
    for(int i = top; i >= 1; --i) {
        for(int j = 0; j < bit[i]; ++j) {
            int temp_mod = (13 - (pre * 10 + j) * MOD[i] % mod) % mod; //计算下以为对应的模。
            ans += dp[i - 1][temp_mod][2];
            if(flag || j == 3 && pre % 10 == 1) //如果已经出现了13了
                ans += dp[i - 1][temp_mod][0];
            else if(j == 1)
                ans += dp[i - 1][temp_mod][1];
        }
        pre = (pre * 10) + bit[i];
        if(i != top && bit[i + 1] == 1 && bit[i] == 3) //判断是否已经出现了13.
            flag = true;
    }
    return ans;
}
int main() {
    init();
    while(~scanf("%d", &a))
        printf("%d\n", f(a + 1));
}



  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值