「题解」带分数

(数学老师:你这是最简分数吗你!)

原题目链接:link


  这道是深搜,平均用时 \(3000\mathrm{ms}\);个人做法是暴力枚举,用时 \(139\mathrm{ms}\)
  但是我不知道这个同学 (变态) \(130\mathrm{ms}\) 是怎么做到的……

biantai's


「我的做题历程」:

step1:观察题面。

  「带分数中,数字 \(1\sim 9\) 分别出现且只出现一次(不包含 \(0\)),输出该数字 \(N\) 用数码 \(1\sim 9\) 不重复不遗漏地组成带分数表示的全部种数」,先闪出的是深搜,但由于想不出怎么搜,转战暴力。(题型:DFS or 暴力枚举)


step2:思考解法。

  抓住带分数构成特点整数+假分数,即 \(x = a + {b\over c}\ (a,b, c \ne 0)\)(假分数可化简为整数,即分子可以整除分母 \((b = kc,\ c\mid b)\) )。
  于是想到先枚举前面的整数 \(a\),然后得到后面的假分数化简的结果 \(k\),通过枚举 \(c\) 来得到 \(b\)。再判断 \(a,b,c\) 是否满足题意即可。
  总不能无限枚举吧,来估范围。分子最小为 \(1\),则整数部分最小为 \(2\),分母最大可取 \(9876543\),还能得到当数 \(N\) 大于 \(9876545\) 时无解(然而 \(N \le 10^6\) ,这个 \(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 👋👋

posted @ 2022-07-21 15:08  北柒kylin  阅读(200)  评论(0编辑  收藏  举报