(数学老师:你这是最简分数吗你!)
原题目链接:link
这道是深搜,平均用时
3000
m
s
3000\mathrm{ms}
3000ms;个人做法是暴力枚举,用时
139
m
s
139\mathrm{ms}
139ms。
但是我不知道这个同学 (变态)
130
m
s
130\mathrm{ms}
130ms 是怎么做到的……
「我的做题历程」:
step1:观察题面。
「带分数中,数字 1 ∼ 9 1\sim 9 1∼9 分别出现且只出现一次(不包含 0 0 0),输出该数字 N N N 用数码 1 ∼ 9 1\sim 9 1∼9 不重复不遗漏地组成带分数表示的全部种数」,先闪出的是深搜,但由于想不出怎么搜,转战暴力。(题型:DFS or 暴力枚举)
step2:思考解法。
抓住带分数构成特点:整数+假分数,即
x
=
a
+
b
c
(
a
,
b
,
c
≠
0
)
x = a + {b\over c}\ (a,b, c \ne 0)
x=a+cb (a,b,c=0)(假分数可化简为整数,即分子可以整除分母
(
b
=
k
c
,
c
∣
b
)
(b = kc,\ c\mid b)
(b=kc, c∣b) )。
于是想到先枚举前面的整数
a
a
a,然后得到后面的假分数化简的结果
k
k
k,通过枚举
c
c
c 来得到
b
b
b。再判断
a
,
b
,
c
a,b,c
a,b,c 是否满足题意即可。
总不能无限枚举吧,来估范围。分子最小为
1
1
1,则整数部分最小为
2
2
2,分母最大可取
9876543
9876543
9876543,还能得到当数
N
N
N 大于
9876545
9876545
9876545 时无解(然而
N
≤
1
0
6
N \le 10^6
N≤106 ,这个
N
N
N 的范围毫无用处)。
step3:完成代码。
代码(抵制学术不端行为,拒绝 Ctrl + C):#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
int n, sum;
bool vis[11]; // 用于判断数码是否重复、遗漏
inline bool nosame(int x) { // 判断一个数的数码是否重复
memset(vis, 0, sizeof vis);
while (x != 0) {
if (vis[x % 10] || x % 10 == 0) {
return false;
}
vis[x % 10] = true;
x /= 10;
}
return true;
}
inline int len(int x) { // 获取该数位数(长度)
int l = 0;
while (x != 0) {
l++;
x /= 10;
}
return l;
}
inline bool nopublic(int a, int b, int c) { // 判断带分数中有无重复的数码
memset(vis, 0, sizeof vis);
while (a != 0) {
vis[a % 10] = true;
if (a % 10 == 0) {
return false;
}
a /= 10;
}
while (b != 0) {
if (vis[b % 10] || b % 10 == 0) {
return false;
}
vis[b % 10] = true;
b /= 10;
}
while (c != 0) {
if (vis[c % 10] || c % 10 == 0) {
return false;
}
vis[c % 10] = true;
c /= 10;
}
return true;
}
inline void get(int x) {
int l = len(n - x);
// 枚举倍数
for (int i = 1; i <= 9876543; i++) { // 分子至少为一,整数部分就只能为二,分母最大可取 9876543
if (nosame(x * i) && nosame(i) && nopublic(x * i, i, n - x) && len(x * i) + len(i) + l == 9) {
printf("%d=%d+%d/%d\n", n, n - x, x * i, i);
sum++;
}
if (len(x * i) + len(i) + l > 9) { // 如果数码大于 9 位就不用再算了
break;
}
}
return;
}
int main() {
freopen("fraction.in", "r", stdin);
freopen("fraction.out", "w", stdout);
while (~scanf("%d", &n)) {
sum = 0;
for (int i = 1; i < n; i++) {
if (nosame(i)) {
get(n - i);
}
}
printf("%d\n", sum);
}
return 0;
}
数据 Hack 了呢~你的 Accepted 被 Hack 掉了吗~( ̄y▽, ̄)╭
让我们来解决 『带分数』 叭~
Bye bye!!1 👋👋