HDU 3652 B-number (数位DP)

Description

统计区间\([1,n]\)中是\(13\)的倍数且数字中含有“13”的数的个数。

Input

多组用例,处理到文件尾。每组用例给出一个整数\(n\)\(1 \leqslant n \leqslant 10^9\)

Output

对于每组用例输出一行,表示区间中满足条件的数的数量。

Sample Input

13
100
200
1000

Sample Output

1
1
2
2

Solution

数位DP。要满足的条件有两个:1. 是\(13\)的倍数。2. 含有“13”。

\(dp[pos][r][s][f]\)\(pos\)表示统计的是第\(pos\)到第\(0\)位,\(r\)表示前面的数位对当前产生的余数,\(s\)表示上一位是否为\(1\)\(f\)表示处理到目前为止是否已经有了\(13\)

如果前面的位置产生的余数是\(r\),当前\(pos\)位的数字是\(i\),那么传给\(pos-1\)位的余数就是\((r+i) \times 10 \mod 13\)

如果上一位是\(1\),也就是\(s\)\(true\),且当前位为\(3\)时,说明出现了\(13\)\(f\)标记为\(true\)

当所有的位置都处理完毕,当且仅当余数为\(0\)\(f\)\(true\)时,说明产生了一个合法的数。

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 15;

int dp[N][15][2][2], a[N];

int dfs(int pos, int r, bool s, bool f, bool fp)
{
	if (pos < 0) return r == 0 && f;
	if (!fp && dp[pos][r][s][f] != -1) return dp[pos][r][s][f];
	int ans = 0, fpmax = fp ? a[pos] : 9;
	for (int i = 0; i <= fpmax; i++)
		ans += dfs(pos - 1, (r + i) * 10 % 13, i == 1, f || s && i == 3, fp && i == fpmax);
	if (!fp) dp[pos][r][s][f] = ans;
	return ans;
}

int calc(int n)
{
	int len = 0;
	while (n) a[len++] = n % 10, n /= 10;
	return dfs(len - 1, false, false, 0, true);
}

int main()
{
	int n;
	memset(dp, -1, sizeof(dp));
	while (~scanf("%d", &n))
	{
		printf("%d\n", calc(n));
	}
	return 0;
}

http://acm.hdu.edu.cn/showproblem.php?pid=3652

posted @ 2017-08-24 11:46  达达Mr_X  阅读(176)  评论(0编辑  收藏  举报