【dp】B-number

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3652

题解:先预处理([0,0][1,1],[2,2]....[0,9],[10, 19],[20,29]......[900000000, 1000000000]  区域中 有子串13 (用1表示)余数为0,1,2.。。12的个数。以及 无子串13(用0表示)余数为0,1,2,3.。。12 的个数。

四维数组dp【一共多少位数】【最高位的数】【是否含有子串13】【余数】 例如  dp[4][1][1][0] 表示 (【1000,2000))(四位, 最高位数为1), 子串中含有13, 且余数为0的个数。

 dp[a][b][c][d] 

当求a = 2时必须 a=1的元素都已知,例如 求[20, 29)中含有13, 余数为3的个数。 即 dp【2】【2】【0】【3】 ,由于 [20, 29)可看做 20 + x(0—9)。而20 % 13 = 7, 只需找余数为9. 则 sum( dp【1】【j】【0】【9】)(j= 0,1,2.。。。9)。

需注意的是 当b = 1 时, 由于在低一位上有3,  所以这种情况要分开求。

 

 

/***Good Luck***/
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <stack>
#include <map>
#include <queue>
#include <vector>
#include <set>
#include <functional>
#include <cmath>
#include <numeric>

#define Zero(a) memset(a, 0, sizeof(a))
#define Neg(a)  memset(a, -1, sizeof(a))
#define All(a) a.begin(), a.end()
#define PB push_back
#define inf 0x3f3f3f3f
#define inf2 0x7fffffffffffffff
#define ll long long
using namespace std;
//#pragma comment(linker, "/STACK:102400000,102400000")
void get_val(int &a) {
    int value = 0, s = 1;
    char c;
    while ((c = getchar()) == ' ' || c == '\n');
    if (c == '-') s = -s; else value = c - 48;
    while ((c = getchar()) >= '0' && c <= '9')
        value = value * 10 + c - 48;
    a = s * value;
}
const int maxn = 20;
int dp[maxn][maxn][2][maxn];
int n;

void change1(int i, int j, int m) {
    for (int k = 0; k <= 1; ++k)
    for (int kk = 0; kk <= 12; ++kk) {
        dp[i][j][1][(kk - m + 13) % 13] += dp[i - 1][3][k][kk];  
    }
}

void change2(int i, int m,int j, int jj) {
    for (int k = 0; k <= 1; ++k)
    for (int kk = 0; kk <= 12; ++kk) {
        dp[i][j][k][(kk + m) % 13] += dp[i - 1][jj][k][kk];
    }
}
void init() {
    Zero(dp);
    int w = 10, m;
    dp[0][0][0][0] = 1;
    for (int i = 0; i <= 10; ++i) dp[1][i][0][i] = 1;
    for (int i = 2; i <= 9; ++i) {
        for (int j = 0; j <= 9; ++j) {
            
            for (int jj = 0; jj <= 9; ++jj) {
                m = (j * w) % 13;
                if (j == 1 && jj == 3) {
                    m = (jj * w / 10 )% 13;
                    change1(i, j, m);
                } else
                    change2(i, m, j, jj);
            }
        }
        w *= 10;
    }
}

int cal(int n1) {
    if (n1 == 1000000000) return 5993844;
    char ch[15];
    Zero(ch);
    int i = 1;
    int flag = -1;
    int ret = 0;
    while (n1) {
        ch[i++] = n1 % 10 + '0';
        n1 /= 10;
    }
    for (int j = i - 1; j > 0; --j) {
        if (ch[j] == '1' && ch[j - 1] == '3') {
            flag = j - 1;
            break;
        }
    }
    n1 = n / 10;
    int w = 1;
    for (int j = 1; j <= i; ++j) {
        for (int jj = 0; jj < ch[j] - '0'; ++jj) {
            int t = (n1 * 10 ) * w % 13;
            if (jj == 3 && ch[j + 1] == '1') {
                t = (n1 / 10 * 100) * w % 13;
                ret += dp[j][0][0][(13 - t) % 13] + dp[j ][0][1][(13 - t) % 13];
                continue;
            }
            if (flag > j) {
                ret += dp[j][jj][0][(13 - t) % 13] + dp[j][jj][1][(13 - t) % 13];
            } else {
                ret += dp[j][jj][1][(13 - t) % 13];
            }
        }
        w *= 10;
        n1 /= 10;
    }
    if (n % 13 == 0 &&  flag != -1) ret++;
    return ret;
}
int main() {
    //freopen("data.out", "w", stdout);
    //freopen("data.in", "r", stdin);
    //cin.sync_with_stdio(false);
    init();
    while (cin >> n) {
        cout << cal(n) << endl;
    }
    return 0;
}

 

posted @ 2014-09-25 19:01  yeahpeng  阅读(118)  评论(0编辑  收藏  举报