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;
}

时间: 2024-08-11 07:47:22

HDU 3652 B-number 数位DP的相关文章

hdu 5787 K-wolf Number 数位dp

数位DP 神模板 详解 为了方便自己参看,我把代码复制过来吧 // pos = 当前处理的位置(一般从高位到低位) // pre = 上一个位的数字(更高的那一位) // status = 要达到的状态,如果为1则可以认为找到了答案,到时候用来返回, // 给计数器+1. // limit = 是否受限,也即当前处理这位能否随便取值.如567,当前处理6这位, // 如果前面取的是4,则当前这位可以取0-9.如果前面取的5,那么当前 // 这位就不能随便取,不然会超出这个数的范围,所以如果前面取

hdu 5898 odd-even number 数位DP

odd-even number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 716    Accepted Submission(s): 385 Problem Description For a number,if the length of continuous odd digits is even and the length

HDU 3709 Balanced Number (数位DP)

Balanced Number Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submission(s): 3798    Accepted Submission(s): 1772 Problem Description A balanced number is a non-negative integer that can be balanced if a pi

hdu 5898 odd-even number(数位dp)

Problem Description For a number,if the length of continuous odd digits is even and the length of continuous even digits is odd,we call it odd-even number.Now we want to know the amount of odd-even number between L,R(1<=L<=R<= 9*10^18). Input Fir

hdu 3565 Bi-peak Number 数位dp

题意:各位数字先增后减的数称为峰值数(位数大于等3且第一位非零),然后两个峰值数连在一起是一个Bi-peak数, 求两个数之间Bi-peak数的各位数字之和的最大值. 思路:设dp[pos][i][j]表示当前考虑pos位,之前的数位为i,状态为j,与之后(pos+1)位组合构成Bi-peak number,这(pos+1)位数位和的 最大值.状态总共有7种,st=0,初始状态:st=1,恰好有一个在第一个波峰的上坡上:st=2,前面至少有两个在第一个波峰的上 坡上; st=3,在第一个波峰的下

HDU 3652 B-number(数位DP)

题意:统计区间 [1,n] 中含有 '13' 且模 13 为 0 的数字有多少个. 分析:由 (HDU 2089 不要62)和(CF 55D - Beautiful numbers)想到该题做法,dp[i][j][f][mod],长度为i,前缀是否为1,是否已符合条件,余数为mod的数字个数. #include <map> #include <set> #include <list> #include <cmath> #include <queue&g

HDU 2089 不要62(数位DP,三种姿势)

HDU 2089 不要62(数位DP,三种姿势) ACM 题目地址:HDU 2089 题意: 中文题意,不解释. 分析: 100w的数据,暴力打表能过 先初始化dp数组,表示前i位的三种情况,再进行推算 直接dfs,一遍搜一变记录,可能有不饥渴的全部算和饥渴的部分算情况,记录只能记录全部算(推荐看∑大的详细题解Orz) 代码: 1. 暴力 (以前写的) /* * Author: illuz <iilluzen[at]gmail.com> * File: 2089_bf.cpp * Create

hdu 3555 Bomb(数位dp)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3555 题目大意:就是给你一个数n,判断从0到n有多少个数含有数字49...... 是不是觉得跟hdu2089很相似呀... 思路:跟hdu2089一样的,注意给出的数比较大,所以这儿用__int64  .... code: #include<cstdio> #include<iostream> #include<cstring> #include<algorithm&

[ACM] hdu 2089 不要62(数位Dp)

不要62 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 19043    Accepted Submission(s): 6442 Problem Description 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer). 杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就

Hdu3079Balanced Number数位dp

枚举支点,然后就搞,记录之前的点的力矩和. #include <cstdio> #include <cstring> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <cstdlib> #include <list> #include <s