HDU 3652 B-number

来源:互联网 发布:测试脸型软件 编辑:程序博客网 时间:2024/05/16 12:04

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
131002001000
 

Sample Output
1122
 

Author
wqb0039
 

Source
2010 Asia Regional Chengdu Site —— Online Contest
 

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) % 13void 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 0
原创粉丝点击