【题目链接】
【算法】
数位DP
f[i][j][k][l]表示i位数,第一位为j,除以13的余数为k,是/否包括子串“13”的方案数
当然,我们也可以先打表,然后,对于每次询问,二分即可
【代码】
#include<bits/stdc++.h> using namespace std; #define MAXL 13 int i,n; int a[MAXL],r[MAXL]; int f[MAXL][10][13][2]; inline void dp() { int i,j,k,x,m; for (i = 0; i <= 9; i++) f[1][i][i][0] = 1; for (i = 2; i < MAXL; i++) { for (j = 0; j <= 9; j++) { for (k = 0; k <= 12; k++) { m = (r[i-1] * j) % 13; for (x = 0; x <= 9; x++) { if (j == 1 && x == 3) continue; f[i][j][k][0] += f[i-1][x][(k-m+13)%13][0]; } for (x = 0; x <= 9; x++) { f[i][j][k][1] += f[i-1][x][(k-m+13)%13][1]; } if (j == 1) f[i][j][k][1] += f[i-1][3][(k-m+13)%13][0]; } } } } inline int calc(int n) { int i,j,len = 0,ans = 0,m = 0,flag = false; memset(a,0,sizeof(a)); while (n) { a[++len] = n % 10; n /= 10; } for (i = len; i >= 1; i--) { if (flag) { for (j = 0; j < a[i]; j++) { ans = ans + f[i][j][(13-m)%13][0] + f[i][j][(13-m)%13][1]; } } else { for (j = 0; j < a[i]; j++) { ans += f[i][j][(13-m)%13][1]; } if (a[i+1] == 1 && a[i] > 3) ans += f[i][3][(13-m)%13][0]; } m = (m + a[i] * r[i-1]) % 13; if (a[i] == 3 && a[i+1] == 1) flag = true; } return ans; } int main() { r[0] = 1; for (i = 1; i < MAXL; i++) r[i] = (r[i-1] * 10) % 13; dp(); while (scanf("%d",&n) != EOF) printf("%d\n",calc(n+1)); return 0; }