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
13 100 200 1000
Sample Output
1 1 2 2
捋一下思路:我们知道我们要的是这样的一个数,数中的子串存有“13”,并且,这个数还能被13整除的这样的一个数,然后就是数位DP的模板,但是……我好弱,敲不来,只能看着大牛的板子一步步的跟着写,我来写下我的思路:看板子得出来的总结。
对于数位DP,我们要做以下的处理:首先,是确定它的状态,对于这道题我们的状态有完全状态【0】:就是指之前没有出现13,并且也不是出现值“1”的情况;下一个状态是状态【1】:指的是这一位是“1”的情况,而且之前没出现过“13”的情况;最后的状态是【2】:指的是之前已经出现过了“13”,接下来就直接推这个状态就行了。
对了,这样子,不做出任何优化的话,时间复杂度就会很高,所以,我们得作出优化就是我们可以记忆化这样的操作,同样的值,我们跑下去,在通过另一种方式跑到,会浪费同样的计算时间,不如就给dp[][][]的初始化赋值为“-1”这样子,遇到不是“-1”的,就说明已经赋值过了,但是,若是遇到有限制的dp[][][],还真不能直接赋值,因为后面的状态会是不一样的,所以,也是需要改变的,那么,我们赋值只能是不受limit限制的,才能通过记忆化的方式给予赋值,
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
using namespace std;
typedef unsigned long long ull;
typedef long long ll; //dp[i][j][k]表示的是目前访问到第i位,此时的余数是j,存在的k种状态
int N, dp[10][27][3]; //状态:【0】合法状态;【1】不存在不吉利,目前位是1,那么如果下一位是3的话,外带能被13整除,就是合法的了;【2】已经出现了13这个数了(再整除的话就是合法数了)——其中,我将13看作不合法数字,以此类推
int digit[15];
int dfs(int pos, int mod, int state, bool limit) //pos记录位置,mod记录模值,state记录状态,limit记录是否是上限
{
int ans = 0;
if(pos <= 0) return mod == 0 && state == 2;
if(!limit && dp[pos][mod][state] != -1) return dp[pos][mod][state];
int num = limit?digit[pos]:9; //是否会取到上限,如果前一位是有限制的话,这一位就是会取到上限,如果前一位就是没有取到上限,那么这一位也是不会取到上限的
int mod_mod_x, new_state; //取到新的状态
for(int i=0; i<=num; i++)
{
mod_mod_x = (mod*10 + i)%13; //能否被13整除的取模情况
new_state = state;
if(state == 0 && i == 1)
{
new_state = 1;
}
if(state == 1 && i != 1)
{
new_state = 0;
}
if(state == 1 && i == 3)
{
new_state = 2; //此时,这个数里含有了13,就有可能是我们要取的数了
}
ans += dfs(pos-1, mod_mod_x, new_state, limit && (i == num));
}
if(!limit) dp[pos][mod][state] = ans;
return ans;
}
inline int solve()
{
int n = N, len = 0;
while(n)
{
digit[++len] = n%10;
n /= 10;
}
return dfs(len, 0, 0, true);
}
inline void init()
{
memset(dp, -1, sizeof(dp));
memset(digit, 0, sizeof(digit));
}
int main()
{
while(scanf("%d", &N)!=EOF)
{
init();
printf("%d\n", solve());
}
return 0;
}