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.
13 100 200 1000
1 1 2 2
给一个数n,让求1-n之间有多少个含有相邻的1、3并且能被13整除的数。解法完全是套模板了,不过第一个题,还是看了人家的才对。
!!!这里的一个问题:::dp数组的第二位mod,也就是dfs的第二个参数mod,这里指的是求得模。到最后判断是return 1 / 0 的标准是:①mod==0;②sta==2。
代码如下:
#include <iostream>
#include <cstring>
using namespace std;
typedef long long LL;
int a[20];
LL dp[20][20][3];
//dp[pos][mod][sta]
//pos: 数位
//mod: 余数
//sta: 3种操作状况,
// 0:末尾不是1, 1:末尾是1, 2:含有13
LL dfs(int pos, int mod, int sta, bool limit)
// 当前位 mod status 是否有上限
{
if (pos <= 0)//最后一位
{
if (mod == 0 && sta == 2)//没有余数 + 有13
return 1;
return 0;
}
if (!limit && dp[pos][mod][sta] != 0)//没有上限 被访问过
return dp[pos][mod][sta];
int up = limit ? a[pos] : 9;
LL temp = 0;
for (int i = 0; i <= up; i++)
{
int mod2 = (mod * 10 + i) % 13;//
int sta2 = sta;
if (sta == 1 && i != 1)//末尾是1,现在加入的不是1
sta2 = 0;//标记为末尾不是1
if (sta == 0 && i == 1)//末尾不是1,现在加入的是1
sta2 = 1;//标记为末尾是1
if (sta == 1 && i == 3)//末尾是1,现在加入的是3
sta2 = 2;//标记为含有13
temp += dfs(pos - 1, mod2, sta2, limit && i == up);
}
if (!limit)
dp[pos][mod][sta] = temp;
return temp;
}
LL solve(int x)
{
int pos = 1;
while (x)
{
a[pos++] = x % 10;
x /= 10;
}
return dfs(pos - 1, 0, 0, 1);
// 首位 mod sta 有上限
}
int main()
{
int n;
while (cin >> n)
{
memset(a, 0, sizeof(a));
memset(dp, 0, sizeof(dp));
cout << solve(n) << endl;
}
return 0;
}