B-number
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2815 Accepted Submission(s): 1552
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以内,含13且被能被13整除的数的个数。
思路:
明显的数位dp。一样的套路,从首位开始,是否是13的倍数,我们不好转移,所以我们考虑保存除以13的余数(*10+新增数,就是转移了).因为要包含‘13’,所以要区分当前状态下有没有‘13’,以及添加一个数之后能不能构成‘13’(当前末尾是否为‘1’)。
还有就是枚举时注意lim,不能超过。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int lim[20];
int dp[20][20][3];
//dp[i][j][k]
//i:数位,j:余数,k:当前状态,0:末尾不是1, 1:末尾是1, 2:含有13
int dfs(int pos, int mod, int cc, int flag){
//flag记录当前状态下是否需要讨论lim(如果前面的位置都达到了lim,那么当前状态下一定要考虑lim)
int num, ans, rmod, rcc;//下一个状态的信息
if(pos <= 0)
return mod == 0 && cc == 2;//唯一结束条件
if(!flag && dp[pos][mod][cc] != -1)//不用考虑上限并且已处理
return dp[pos][mod][cc];
if( flag ) num = lim[pos];//不能超上限
else num = 9;
ans = 0;
for(int i=0; i<=num; i++){
rmod = (mod * 10 + i) % 13;
//判断整除13,
rcc = cc;
if(cc == 0 && i == 1) rcc = 1;//末尾不是1,现在加入的是1
if(cc == 1 && i != 1) rcc = 0;//末尾是1,现在加入的不是1
if(cc == 1 && i == 3) rcc = 2;//末尾是1,现在加入的是3
ans += dfs(pos-1, rmod, rcc, flag && i==num);//之前一直是lim,当前为也是
}
if(!flag)
dp[pos][mod][cc] = ans;
return ans;
}
int main(){
int n;
while( ~scanf("%d", &n) ){
memset(lim, 0, sizeof(lim));
memset(dp, -1, sizeof(dp));
int len = 0;
while( n ){
lim[++len] = n % 10;//每一位的上限
n /= 10;
}
printf("%d\n", dfs(len, 0, 0, 1));//首位是要考虑上限的
}
return 0;
}