Problem Description
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
题意:给你一个数n,找出1~n之间有几个数能被13整除而且含有13。
dp[len][mod][have],len表示当前的位数,mod表示上一位mod 13 的余数,have = 1表示前一位取1,have = 2表示出现过“13”。
思路就是记忆化搜索设置参数flag表示接下来的数是否一定比给的数小。
#include <iostream> #include <cstring> using namespace std; typedef long long ll; ll dp[30][20][3]; ll a[30]; ll dfs(int len , int mod , int have , int flag) { if(len == 0) { return have == 2 && mod == 0; } if(!flag && dp[len][mod][have] != -1) { return dp[len][mod][have]; } int t = flag ? a[len] : 9; ll sum = 0; for(int i = 0 ; i <= t ; i++) { if(have == 0 && i == 1) { sum += dfs(len - 1 , (mod * 10 + i) % 13 , 1 , flag && i == t); } else if(have == 1 && i == 3) { sum += dfs(len - 1 , (mod * 10 + i) % 13 , 2 , flag && i == t); } else if(have == 1 && i != 1) { sum += dfs(len - 1 , (mod * 10 + i) % 13 , 0 , flag && i == t); } else { sum += dfs(len - 1 , (mod * 10 + i) % 13 , have , flag && i == t); } } if(!flag) dp[len][mod][have] = sum; return sum; } ll Get(ll x) { ll gg = x; memset(dp , -1 , sizeof(dp)); memset(a , 0 , sizeof(a)); int len = 0; while(gg) { a[++len] = gg % 10; gg /= 10; } return dfs(len , 0 , 0 , 1); } int main() { ll n; while(cin >> n){ cout << Get(n) << endl; } return 0; }