hdu3652 B-number

题目链接: 3652 ( B-number )

\(dp[i][j][r]\) 代表 \(i\) 位数、首位为 \(j\) 、模 \(13\)\(r\) 、且包含 \(13\) 的数的个数。

则根据 \(i-1\) 的状态可推出 \(i\) 的状态,不同状态间余数 \(r\) 的转换要到位。

\(AC\) 代码:

/**
 * hdu3652 B-number
 *
 */

#include <iostream>
#include <climits>
#include <cmath>
#include <iomanip>
#include <vector>
#include <cstring>
using namespace std;

typedef long long LL;

const int N = 11;
int dp[N][10][13];  // dp[i][j][r]代表首位为j的i位数中包含13且模13余r的数的个数

LL qpow(LL a, LL b, LL mod = LLONG_MAX)
{
    a %= mod;
    LL t = 1;
    while (b) {
        if (b&1) t = t*a%mod;
        a = a*a%mod;
        b >>= 1;
    }
    return t%mod;
}

void init()
{
    for (int i = 2; i < N; ++i) {
        for (int j = 0; j < 10; ++j) {
            for (int k = 0; k < 10; ++k) {
                for (int r = 0; r < 13; ++r) {
                    int rem = (r+j*qpow(10, i-1))%13;
                    if (j == 1 && k == 3) {
                        int t = qpow(10, i-2)-1;
                        if (t >= rem) dp[i][j][rem] += (t-rem)/13+1;
                    }
                    else dp[i][j][rem] += dp[i-1][k][r];
                }
            }
            //cout << dp[i][j][0] << ' ';
        }
        //cout << endl;
    }
}

int digit[N+5];
int solve(int n)
{
    int res = 0;
    int len = 0;
    for (int i = n; i; i /= 10) {
        digit[++len] = i%10;
    }
    digit[len+1] = 0;
    int rem = 0;
    for (int i = len; i; --i) {
        for (int j = 0; j < digit[i]; ++j) {
            if (j == 3 && digit[i+1] == 1) {
                int t = qpow(10, i-1)-1;
                int r = (rem+qpow(10,i-1)*j)%13;
                r = (13-r)%13;
                if (t >= r) res += (t-r)/13+1;
            }
            else res += dp[i][j][(13-rem)%13];
        }
        rem = (rem+qpow(10, i-1)*digit[i])%13;
        if (digit[i+1] == 1 && digit[i] == 3) {
            int t = n%qpow(10, i-1), r = (13-rem)%13;
            if (t >= r) res += (t-r)/13+1;
            break;
        }
    }
    return res;
}

int main()
{
    init();
/*
    for (int i = 0; i <= 10; ++i) {
        cout << i << ": ";
        for (int j = i*100; j < i*100+100; ++j) {
            if (j%10 == 0) cout << endl;
            cout << setw(2) << solve(j) << ' ';
        }
        cout << endl;
    }
*/
    int n;
    while (~scanf("%d", &n)) {
        printf("%d\n", solve(n));
    }

    return 0;
}

posted @ 2021-02-08 22:12  Zewbie  阅读(40)  评论(0)    收藏  举报