HDU 3652 B-number 数位DP

http://acm.hdu.edu.cn/showproblem.php?pid=3652

首先先解决怎么判断它是否含有13这个子串。

方法就类似于一个状态记录dp

加多一维[0 or 1]判断是否已经含有了13这个子串,那么如果枚举的时候,相邻的两位是13,则可由0跳转去1

这题是设dp[i][j][0 or 1][r]表示i位数,以j为开头的,是否含有13这个子串了,然后余数是r( % 13)

至于为什么要加上余数这个条件,

是因为在统计答案的过程中,统计答案的方法和上一篇类似。有些不同的就是需要用余数来判断这一位应该加上那些数字。

因为它是拆分开来的,按位dp

比如26XX,那么XX后面的余数应该是0,这样才能整除以13

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <assert.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;


#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <bitset>
int n;
int dp[12][12][2][15];
LL base[15];
void init() {
    base[0] = 1;
    for (int i = 1; i <= 10; ++i) {
        base[i] = base[i - 1] * 10;
    }
    for (int i = 0; i <= 9; ++i) {
        dp[1][i][0][i] = 1;
    }
    for (int i = 2; i <= 10; ++i) { //枚举一共有i位
        for (int j = 0; j <= 9; ++j) { //枚举第i位
            for (int x = 0; x <= 9; ++x) { //第i - 1位
                int t = base[i - 1] * j % 13;
                for (int r = 0; r <= 12; ++r) {
                    dp[i][j][1][(r + t) % 13] += dp[i - 1][x][1][r];
                    if (j == 1 && x == 3) {
                        dp[i][j][1][(r + t) % 13] += dp[i - 1][x][0][r];
                    } else {
                        dp[i][j][0][(r + t) % 13] += dp[i - 1][x][0][r];
                    }
                }
            }
        }
    }
}
void work() {
    n++;
    int digit[15] = {0};
    int lenstr = 0;
    while (n / 10 > 0) {
        digit[++lenstr] = n % 10;
        n /= 10;
    }
    digit[++lenstr] = n % 10;
    int ans = 0;
    int mod = 0;
    bool flag = false;
    for (int i = lenstr; i >= 1; --i) {
        for (int j = 0; j <= digit[i] - 1; ++j) {
            ans += dp[i][j][1][(13 - mod) % 13];
            if (flag || j == 3 && digit[i + 1] == 1) {
                ans += dp[i][j][0][(13 - mod) % 13];
            }
        }
        if (digit[i] == 3 && digit[i + 1] == 1) {
            flag = true;
        }
        mod = (mod + digit[i] * base[i - 1]) % 13;
    }
    cout << ans << endl;
}
int main() {
#ifdef local
    freopen("data.txt", "r", stdin);
//    freopen("data.txt", "w", stdout);
#endif
    init();
    while (cin >> n) work();
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/liuweimingcprogram/p/6298528.html