1 条题解
-
0
自动搬运
来自洛谷,原作者为

djc
AFO|渺渺兮予怀,望美人兮天一方搬运于
2025-08-24 22:51:55,当前版本为作者最后更新于2023-10-29 08:36:36,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
题目大意
给定一个正整数 ,构造出若干个形如 的真分数,使得 ,且 是 的因数。
题目分析
由于 是 的因数,所以我们直觉上先把 分解一下:
-
在这种情况下,无解。如果 ,那么 ,并且每个 都差了 倍。设最大的一个 为 ,则通分后的分母为 ,而 ,所以不可能凑成 。
-
的质因数大于等于 种
首先,在这种情况下,如果存在答案,那么 一定可以等于 。因为 ,且 ,任意选取两个,,如果 ,我们可以把它们凑成两个。
所以算法的第一步就出来了, 和 任选,只要是 的因数且最小公倍数等于 就可以了,然后我们再看 和 ,是否对于任意的 和 都存在正整数解 且 呢?
先做一个转换,同乘 :
观察这个式子,在学习拓展欧几里得算法时我们学过, 一定是 的倍数,否则无解,由于 一定是 的倍数,所以一定是有解的。
还有就是要证明存在一个 的情况下的解,设 已知,,则 。设 ,则
若有解,则需要 是一个整数,也就是
我们看 ,由于 与 互质,所以当 , 的值都不相同。
证明:如果有两数相同,,则 , 需要是 的倍数。
又因为当 时, 一定不为 ,所以在 到 中一定有一个 使得 。
代码实现
经过以上分析,代码就可以写出来了。我们先把 分解质因数,然后选取 和 ,使 。然后从 到 枚举 ,每次进行一个判断即可。时间复杂度 。
最后贴上代码,码风很丑轻点喷。
#include <bits/stdc++.h> using namespace std; #define int long long #define maxn 100005 inline int read() { int x = 0, f = 1; char c = getchar(); while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); } while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); } return x * f; } int vis[maxn], prime[maxn], n, m; void init() { for (int i = 2; i <= 100000; i++) { if (!vis[i]) prime[++m] = i, vis[i] = 1; for (int j = 1; j <= m && prime[j] * i <= 100000; j++) vis[prime[j] * i] = 1; } } struct node { int v, cnt; }; vector<node> a; int ksm(int a, int b) { int res = 1; for (; b; b >>= 1) { if (b & 1) res = res * a; a = a * a; } return res; } signed main() { init(); n = read(); for (int i = 1; i <= m; i++) { if (n % prime[i] == 0) { int tmp = n, cnt = 0; while (tmp % prime[i] == 0) { cnt++; tmp /= prime[i]; } node nw; nw.cnt = cnt, nw.v = prime[i]; a.push_back(nw); break; } } if (a.empty() || ksm(a[0].v, a[0].cnt) == n) { puts("NO"); return 0; } puts("YES"); int x = ksm(a[0].v, a[0].cnt); int y = n / x, a, b; for (a = 1; a < x; a++) { if ((n - 1 - a * y) % x == 0) { b = (n - 1 - a * y) / x; break; } } cout << 2 << endl; cout << a << " " << x << endl << b << " " << y; } -
- 1
信息
- ID
- 8900
- 时间
- 1750ms
- 内存
- 512MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者