B-number(数位dp)

题目

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

解释

dp[pos][sta][pre][sum]代表第pos位, sta 1代表前面已有13 0反之,pre代表前一位是否为1,sum代表前面数值对13取余的结果。
因为sum的当前值决定了后面有多少个满足余数为0的数,所以要加上sum这一维度,sta和pre合成一个维度判断也可。

#include <cstdio>
#include <cstring>
#define ll long long 
using namespace std;
ll dp[20][2][2][14];
int dig[20];
ll dfs(int pos, int sta, int pre, int sum, int limit){
	if(pos == -1) return sta && !sum ? 1:0;
	if(!limit && dp[pos][sta][pre == 1][sum] != -1) return dp[pos][sta][pre == 1][sum];
	int up = limit? dig[pos]:9;
	ll ans = 0;
	for(int i = 0; i <= up; i++){
		ans += dfs(pos-1, sta||(pre == 1 && i == 3), i, (sum*10+i)%13, limit && i == up);
	}
	if(!limit) dp[pos][sta][pre == 1][sum] = ans;
	return ans; 
}
ll slove(ll x){
	int pos = 0;
	while(x){
		dig[pos++] = x%10;
		x /= 10; 
	}
	ll ans = dfs(pos-1, 0, 0,0, 1);
	return ans;
}
int main(){
	int n;
	memset(dp, -1, sizeof(dp));
	while(~scanf("%d", &n)){
		printf("%I64d\n", slove(n));
	}
	return 0;
}
发布了52 篇原创文章 · 获赞 2 · 访问量 860

猜你喜欢

转载自blog.csdn.net/qq_44714572/article/details/103227834