题目描述:
我们称一个数 X 为好数, 如果它的每位数字逐个地被旋转 180 度后,我们仍可以得到一个有效的,且和 X 不同的数。要求每位数字都要被旋转。
如果一个数的每位数字被旋转以后仍然还是一个数字, 则这个数是有效的。0, 1, 和 8 被旋转后仍然是它们自己;2 和 5 可以互相旋转成对方(在这种情况下,它们以不同的方向旋转,换句话说,2 和 5 互为镜像);6 和 9 同理,除了这些以外其他的数字旋转以后都不再是有效的数字。
现在我们有一个正整数 N
, 计算从 1
到 N
中有多少个数 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]; 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); } };
|