题目描述
AFei loves numbers. He defines the natural number containing “520” as the AFei number, such as 1234520, 8752012 and 5201314. Now he wants to know how many AFei numbers are not greater than n.
输入描述:
The first line contains an integer T (1 <= T <= 100 ).
The following T lines contain an interger n ( 0 <= n <= 1e18 ).
输出描述:
For the last T lines, output the total numbers of AFei numbers that are not greater than n.
输入
2
1000
5520
输出
1
16
说明
For the first case, only 520 is AFei number.
For the second case, 520,1520, 2520, 3520, 4520, 5200, 5201, 5202, 5203, 5204, 5205, 5206, 5207, 5208, 5209 and 5520 are AFei number. So there are 16 AFei numbers.
思路
- 计算不包括520的数字
- dp[ i ][ j ] 表示以数字 j 结尾后面剩余 i 位数字中不包括520的数字的数量
- dp[ i ][ j ] = ∑ k = 0 k = t o p \sum_{k=0}^{k=top} ∑k=0k=topdp[ i - 1 ][ (j % 10) * 10 + k ]
- 计算包括520的数字
- dp[ i ][ j ][ flag ] 表示以数字 j 结尾后面剩余 i 位数字中包括520的数字的数量,其中flag表示走到当前位置是否出现过520
- 为什么加上flag表示? 如果520出现过,递归到0的时候就要+1,否者不加。
// 计算不包括
#include <bits/stdc++.h>
#define LL long long
#define P pair<int, int>
#define lowbit(x) (x & -x)
#define mem(a, b) memset(a, b, sizeof(a))
#define REP(i, n) for (int i = 1; i <= (n); ++i)
#define rep(i, n) for (int i = 0; i < (n); ++i)
#define maxn 100005
using namespace std;
int num[20];
LL dp[20][100];
LL dfs(int len, int pre, int limit) {
if (!len) return 1;
// 使用dp数组,前提limit = 0
if (!limit && dp[len][pre] != -1) return dp[len][pre];
LL sum = 0;
int top = 9;
if (limit) top = num[len];
for (int i = 0; i <= top; ++i) {
if (i == 0 && pre == 52) continue;
sum += dfs(len-1, (pre%10) * 10 + i, limit&&i==top);
}
// 只有在limit = 0 时,更新dp
if (!limit) dp[len][pre] = sum;
return sum;
}
LL solve(LL n) {
int len = 0;
LL t = n;
while (t) {
num[++len] = t % 10;
t /= 10;
}
LL ans = dfs(len, 0, 1);
ans = n + 1 - ans;
printf("%lld\n", ans);
return 0;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
#endif
mem(dp, -1);
int T;
scanf("%d", &T);
while (T--) {
LL n;
scanf("%lld", &n);
solve(n);
}
return 0;
}
// 计算包括
#include <bits/stdc++.h>
#define LL long long
#define P pair<int, int>
#define lowbit(x) (x & -x)
#define mem(a, b) memset(a, b, sizeof(a))
#define REP(i, n) for (int i = 1; i <= (n); ++i)
#define rep(i, n) for (int i = 0; i < (n); ++i)
#define maxn 100005
using namespace std;
int num[20];
LL dp[20][100][2];
LL dfs(int len, int pre, int limit, int flag) {
if (!len) return flag ? 1 : 0;
if (!limit && dp[len][pre][flag] != -1) return dp[len][pre][flag];
int top = limit ? num[len] : 9;
LL sum = 0;
for (int i = 0; i <= top; ++i) {
if (i == 0 && pre == 52) sum += dfs(len-1, (pre%10)*10+i, limit&&i==top, 1);
else sum += dfs(len-1, (pre%10)*10+i, limit&&i==top, flag);
}
if (!limit) dp[len][pre][flag] = sum;
return sum;
}
LL solve(LL n) {
int len = 0;
LL t = n;
while (t) {
num[++len] = t % 10;
t /= 10;
}
LL ans = dfs(len, 0, 1, 0);
printf("%lld\n", ans);
return 0;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
#endif
mem(dp, -1);
int T;
scanf("%d", &T);
while (T--) {
LL n;
scanf("%lld", &n);
solve(n);
}
return 0;
}