题目描述
B数的定义:能被13整除且本身包含字符串"13"的数。
例如:130和2613是B数,但是143和2639不是B数。
你的任务是计算1到n之间有多少个数是B数。
输入
输入数据只有一个数,为n。(\(1<=N<=10^{15}\))
输出
输出数据包含一行,为1到n之间B数的个数。
样例输入
13
样例输出
1
题解
数位DP
记录对13的模数来判断是否可以被13整除。
同时记录是否出现过‘13’, 还要考虑首位前导0的情况。
设\(f[i][j][k][0/1]\)为\(i\)位数,对\(13\)取模结果为\(j\),首位为\(k\),是否包含\(13\)的数的个数。
预处理\(f\)数组后进行数位DP。
先填充位数不满的,再由高位向低位将此位不满的加入答案。
转换询问区间为\([1,n)\)则更易简单处理。
code
#include <iostream> #include <cstdio> using namespace std; typedef long long LL; LL n, b[17], f[17][13][10][2]; void init() { b[0] = f[0][0][0][0] = 1; for(int i = 1;i <= 16;i ++) { b[i] = b[i-1] * 10; for(int j = 0;j < 13;j ++) { for(int k = 0;k <= 9;k ++) { for(int l = 0;l <= 9;l ++) { f[i][(j+k*b[i-1])%13][k][1||(k==1&&l==3)] += f[i-1][j][l][1]; f[i][(j+k*b[i-1])%13][k][0||(k==1&&l==3)] += f[i-1][j][l][0]; } } } } } int main() { init(); while(cin >> n) { int x = n + 1; int pos , j, di = 1 , flag = 0; LL now = 0 , ans = 0; for(pos = 1 ; b[pos] <= x ; pos ++ ) for(j = 1 ; j < 10 ; j ++ ) ans += f[pos][0][j][1]; for( ; pos ; pos -- ) { for(j = di ; j < x / b[pos - 1] % 10 ; j ++ ) ans += f[pos][(13 - now * b[pos] % 13) % 13][j][1] + (flag || (x / b[pos] % 10 == 1 && j == 3)) * f[pos][(13 - now * b[pos] % 13) % 13][j][0]; now = (now * 10 + x / b[pos - 1] % 10) % 13 , di = 0; if(x / b[pos] % 10 == 1 && x / b[pos - 1] % 10 == 3) flag = 1; } cout << ans << endl; } return 0; }