看了这篇题解,写得超级棒。
dp[i][j]
表示一共i位,首位为j的数有多少是符合要求的。
用一个k记录上一位。
先把这个数组全都预处理出来,我一开始位数是从0到LEN,但是预处理的时候不是很方便,就换成从1开始了。
然后处理比n小的数有多少符合要求的。
先把n每位拆开存在d数组里,要注意它是从低位开始存的,但是后面我们是从高位往低位扫,所以是它的上一位是6要写成d[i + 1] == 6
,我这里错了好久。
从高位往低位扫,比如n = 1346,先加上0xxx,接着加上0xx、1xx、2xx,然后0x、1x、2x、3x,出现了一个4!就退出来好了,后面的都不会符合要求了,不用费事了。
62也差不多。
注意细节就好了。
#include <cstdio>
#include <cstring>
using namespace std;
const int LEN = 7;
int dp[LEN][10], d[LEN];
int n, m;
void prepare()
{
dp[0][0] = 1;
for (int i = 1; i <= LEN; i++)
{
for (int j = 0; j <= 9; j++)
{
if (j != 4)
{
for (int k = 0; k <= 9; k++)
{
if (!(j == 6 && k == 2))
{
dp[i][j] += dp[i - 1][k];
}
}
}
//printf("%d %d : %d\n", i, j, dp[i][j]);
}
}
}
int solve(int n)
{
memset(d, 0, sizeof(d));
int len = 0;
while (n)
{
d[len + 1] = n % 10;
n /= 10;
len++;
}
int ans = 0;
for (int i = len; i >= 1; i--)
{
for (int j = 0; j < d[i]; j++)
{
//if (d[i + 1] != 6 || j != 2) ans += dp[i][j];
if (!(j == 2 && d[i + 1] == 6)) ans += dp[i][j];
}
if (d[i] == 4 || (d[i + 1] == 6 && d[i] == 2)) break;
}
return ans;
}
int main()
{
prepare();
while (scanf("%d %d", &n, &m))
{
if (n == 0 && m == 0) return 0;
printf("%d\n", solve(m + 1) - solve(n));
}
return 0;
}
【我太辣鸡了,对不起。】