0%

788. 旋转数字

788.旋转数字

题目描述:

我们称一个数 X 为好数, 如果它的每位数字逐个地被旋转 180 度后,我们仍可以得到一个有效的,且和 X 不同的数。要求每位数字都要被旋转。

如果一个数的每位数字被旋转以后仍然还是一个数字, 则这个数是有效的。0, 1, 和 8 被旋转后仍然是它们自己;2 和 5 可以互相旋转成对方(在这种情况下,它们以不同的方向旋转,换句话说,2 和 5 互为镜像);6 和 9 同理,除了这些以外其他的数字旋转以后都不再是有效的数字。

现在我们有一个正整数 N, 计算从 1N 中有多少个数 X 是好数?

数据范围:

$1\le n \le 10000$

题解:

数字集合为 $[0,1,2,5,6,8,9]$ ,和上一题非常类似,也是需要前导零,但是这个集合里面包括 $0$ ,因此循环需要从 $isLead$ 开始枚举。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
auto optimize_cpp_stdio = []()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
return 0;
}();
class Solution
{
public:
const static int maxn = 1e5 + 10;
const static int maxm = 1e5 + 10;
const int INF = 0x3f3f3f3f;
vector<int> num = {0, 1, 2, 5, 6, 8, 9};
int len;
string s;
int dp[5][2];
// flag 是否存在 2, 5, 6, 9
int dfs(int step, bool flag, bool isLimit, bool isLead)
{
if (step == len)
return !isLead && flag;
if (!isLimit && !isLead && dp[step][flag] != -1)
return dp[step][flag];
int up = isLimit ? s[step] - '0' : 9;
int ans = 0;
if (isLead)
ans += dfs(step + 1, false, false, true);
for (int i = isLead; i < num.size(); ++i)
{
if (num[i] > up)
break;
ans += dfs(step + 1, flag | (num[i] == 2 || num[i] == 5 || num[i] == 6 || num[i] == 9), isLimit && num[i] == up, false);
}
if (!isLimit && !isLead)
dp[step][flag] = ans;
return ans;
}
int rotatedDigits(int n)
{
s = to_string(n);
len = s.length();
memset(dp, -1, sizeof(dp));
return dfs(0, false, true, true);
}
};