Link Title: http://acm.hdu.edu.cn/showproblem.php?pid=3555
Title effect: seeking \ ([1, n] \ ) in a range comprising a plurality few "49."
Problem-solving ideas:
This is something we can be divided into two solutions to consider: the first is seeking does not include the number of the number "49" after reducing it by; the other is the direct request contains the number of the number "49" is.
Solution 1: Find the number does not include the number "49"
By this method we first determined the number of bits the DP \ ([0, n-] \) interval does not include the range of a small number of multiple "49" (the number is assumed to be \ (X \) ), then the answer is \ (n + -the X-1 \) .
We can design a function dfs(int pos, int stat, bool limit)
that returns the interval \ ([0, n] \ ) in the range of a few does not contain a number, "49", wherein:
pos
It represents the digit is currently located;stat
Pre represents a number is not '4' (if the former is '4' is the current location '9' to make up the "49");limit
For labeling currently restricted (true: Restricted; false: unlimited).
Codes are as follows:
#include <bits/stdc++.h>
using namespace std;
long long f[66][2], n;
int T, a[66];
void init() {
memset(f, -1, sizeof(f));
}
long long dfs(int pos, int stat, bool limit) {
if (pos < 0) return 1;
if (!limit && f[pos][stat] != -1) return f[pos][stat];
int up = limit ? a[pos] : 9;
long long tmp = 0;
for (int i = 0; i <= up; i ++) {
if (stat && i == 9) continue;
tmp += dfs(pos-1, i==4, limit && i == up);
}
if (!limit) f[pos][stat] = tmp;
return tmp;
}
long long get_num(long long x) {
int pos = 0;
while (x) {
a[pos++] = x % 10;
x /= 10;
}
return dfs(pos-1, 0, true);
}
int main() {
init();
scanf("%d", &T);
while (T --) {
scanf("%lld", &n);
printf("%lld\n", n+1-get_num(n));
}
return 0;
}
Solution 2: Please include how many number "49"
Solution 1 is relatively indirect way to solve it. We are now in this way is directly solving \ ([0, n] \ ) within a range of how many contain the number "49."
We can design a function dfs(int pos, int stat, bool limit)
that returns the interval \ ([0, n] \ ) in the range of a few does not contain a number, "49", wherein:
pos
It represents the digit is currently located;stat
Pre represents a number is not '4' (if the former is '4' is the current location '9' to make up the "49");limit
For labeling currently restricted (true: Restricted; false: unlimited).
Although it is the same, but when dealing with statistics is not the same way.
It should be noted in particular restrictions under different processing conditions and non-limiting.
Suppose we are looking for is the interval \ ([0, n] \ ) in a range comprising a plurality few "49" is traversed pos
bits and pos+1
bits are '4', pos
the bit is '9', then we can see that:
- If the current state is the limit, then there is \ (n \% 10 ^ { pos} + 1 \) number satisfying the condition;
- If the current state is in a non-limiting, the following has \ (10 ^ {pos} \ ) number satisfying the condition.
Codes are as follows:
#include <bits/stdc++.h>
using namespace std;
long long f[66][2], n;
int T, a[66];
void init() {
memset(f, -1, sizeof(f));
}
long long pow10(int a) {
if (a == 0) return 1;
if (a == 1) return 10;
long long t = pow10(a/2);
return t * t * (a%2 ? 10 : 1);
}
long long dfs(int pos, int stat, bool limit) {
if (pos < 0) return 0; // 返回0说明没找到包含49的
if (!limit && f[pos][stat] != -1) return f[pos][stat];
int up = limit ? a[pos] : 9;
long long tmp = 0;
for (int i = 0; i <= up; i ++) {
if (stat && i == 9) { // 说明接下来pos位的10的pos次方个数都满足条件
// tmp += pow10(pos); // 直接这么写是错的,此时也要考虑边界条件限制
// 修正如下
if (limit) tmp += n % pow10(pos) + 1;
else tmp += pow10(pos);
}
else tmp += dfs(pos-1, i==4, limit && i == up);
}
if (!limit) f[pos][stat] = tmp;
return tmp;
}
long long get_num(long long x) {
int pos = 0;
while (x) {
a[pos++] = x % 10;
x /= 10;
}
return dfs(pos-1, 0, true);
}
int main() {
init();
scanf("%d", &T);
while (T --) {
scanf("%lld", &n);
printf("%lld\n", get_num(n));
}
return 0;
}