>Link
ybtojB数计数
>Description
求1到n当中有多少个数满足:十进制下既包含子串"13",又能被13整除
其中
1
≤
n
≤
1
0
9
1≤n≤10^9
1≤n≤109
>解题思路
数位DP的模板题
#==
一直RE调试了超级久,后来搜系统信息“Killed: Floating point exception”,看到有人说是除0的情况,但是我的码并没有除0的情况啊😅又调了好久,无奈之下把原来的方法改成不用除法的方法,然后就A了😅
f
i
,
j
,
k
f_{i,j,k}
fi,j,k表示前面填了
i
i
i位数,当前的余数为
j
j
j,包含"13"的状态为
k
k
k
k
k
k的含义:
- k = = 0 k==0 k==0:当前不包含"13"
- k = = 1 k==1 k==1:当前最后一位为"1"
- k = = 2 k==2 k==2:当前已包含"13"
我们DP,不断在后面添数,就可以算出来了。状态如何转移挺好推的,需要分类讨论,要注意下当前为1和3的情况
但是范围规定了1到n
设n有m位
位数小于m位的,显然每位数的位置可以随便填
位数等于m位的,可以发现,如果当前位填的数比
n
n
n对应位上的数小,那么后面位上的数就可以随便填
我们可以直接枚举
i
i
i,表示
i
i
i之前的位都和
n
n
n对应,让第
i
i
i位填一个较小的数,后面的位置进行乱填,维护一下就行了(数据范围很小)
>代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n, m, t, p, a[20], f[20][20][5], ff[20][20][5], ans, pmod;
void solve (int S, int T, int E)
{
memset (ff, 0, sizeof (ff));
for (int j = 0; j < 13; j++)
for (int k = 0; k < 3; k++)
ff[S - 1][j][k] = f[S - 1][j][k];
for (int i = S; i <= T; i++)
{
for (int j = 0; j < 13; j++)
for (int k = 0; k < 10; k++)
{
int p = (j * 10 % 13 + k) % 13;
if (k == 1)
ff[i][p][1] += ff[i - 1][j][0] + ff[i - 1][j][1];
else ff[i][p][0] += ff[i - 1][j][0];
if (k != 1 && k != 3) ff[i][p][0] += ff[i - 1][j][1];
if (k == 3) ff[i][p][2] += ff[i - 1][j][1];
ff[i][p][2] += ff[i - 1][j][2];
}
if (E) ans += ff[i][0][2];
}
if (!E) ans += ff[T][0][2];
}
int main()
{
while (scanf ("%d", &n) != EOF)
{
ans = m = 0;
memset (f, 0, sizeof (f));
memset (a, 0, sizeof (a));
t = 1;
while (n / t > 0) t *= 10, m++;
//for (t = 1; n / t != 0; t *= 10) m++;
//t /= 10;
//for (int i = 1; i <= m; i++)
// a[i] = n / t % 10, t /= 10;
for (int i = 1; i <= m; i++)
a[m - i + 1] = n % 10, n /= 10; //a记录n第几位上填的是什么数
for (int i = 2; i < 10; i++)
f[1][i][0] = 1;
f[1][1][1] = 1;
solve (2, m - 1, 1);
memset (f, 0, sizeof (f));
pmod = 0; //pmod记录当前枚举到的位置,前面的余数是多少(对于n而言)
for (int i = 1; i <= m; i++)
{
if (i == 1)
{
for (int k = 1; k < a[i]; k++)
{
if (k == 1) f[i][k][1] = 1;
else f[i][k][0] = 1;
solve (i + 1, m, 0);
if (k == 1) f[i][k][1] = 0;
else f[i][k][0] = 0;
}
if (a[i] == 1) f[i][a[i]][1] = 1;
else f[i][a[i]][0] = 1;
pmod = a[i];
continue;
}
for (int k = 0; k < a[i]; k++)
{
p = (pmod * 10 % 13 + k) % 13;
if (k == 1)
f[i][p][1] += f[i - 1][pmod][0] + f[i - 1][pmod][1];
else f[i][p][0] += f[i - 1][pmod][0];
if (k != 1 && k != 3) f[i][p][0] += f[i - 1][pmod][1];
if (k == 3) f[i][p][2] += f[i - 1][pmod][1];
f[i][p][2] += f[i - 1][pmod][2];
solve (i + 1, m, 0);
if (k == 1)
f[i][p][1] -= f[i - 1][pmod][0] + f[i - 1][pmod][1];
else f[i][p][0] -= f[i - 1][pmod][0];
if (k != 1 && k != 3) f[i][p][0] -= f[i - 1][pmod][1];
if (k == 3) f[i][p][2] -= f[i - 1][pmod][1];
f[i][p][2] -= f[i - 1][pmod][2];
}
p = (pmod * 10 % 13 + a[i]) % 13;
if (a[i] == 1)
f[i][p][1] += f[i - 1][pmod][0] + f[i - 1][pmod][1];
else f[i][p][0] += f[i - 1][pmod][0];
if (a[i] != 1 && a[i] != 3) f[i][p][0] += f[i - 1][pmod][1];
if (a[i] == 3) f[i][p][2] += f[i - 1][pmod][1];
f[i][p][2] += f[i - 1][pmod][2];
pmod = p;
}
ans += f[m][0][2];
printf ("%d\n", ans);
}
return 0;
}