1 条题解
-
0
#include <bits/stdc++.h> using namespace std; /* * 题意回顾 * 给定 x,考虑由 x 的因子(每个都 > 1)组成的序列 d1, d2, ..., dk,要求 d_i | d_{i+1}。 * 问:最大长度 k,以及具有该最大长度的不同序列的个数。 * * 重要结论(经典结论): * 设 x 的素因子分解为 x = p1^a1 * p2^a2 * ... * pm^am, * 记 L = a1 + a2 + ... + am(素因子个数的“重数和”,又记为 Ω(x))。 * 1) 能达到的最大长度 = L。 * 证明直观:把序列看作“从某个质因子开始,每一步把某个素因子指数 +1”, * 想要长度尽可能长,就必须一步只增加 1(即每次只乘上一个素因子), * 最多能增加到总指数和 L;且第一项必须是某个质因子(>1),否则少一步。 * 2) 达到最大长度 L 的序列条数 = 将多重集合 {p1×(a1 个), p2×(a2 个), ...} 排序的种数, * 即多重集排列数: L! / (a1! * a2! * ... * am!) * * 因此做法: * - 试除分解 x(x ≤ 2^20,最多 1e6 级,简单试除即可)。 * - L 取指数和。 * - 计数为多重排列数,可用阶乘比值:ans = fact[L] / Π fact[ai]。 * 这里 L ≤ 20(因为 x ≤ 2^20),20! 在 64 位整数范围内,安全。 */ // 预计算 0..20 的阶乘(20! = 2,432,902,008,176,640,000 < 2^63-1) static unsigned long long fact[21]; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); // 预计算阶乘 fact[0] = 1; for (int i = 1; i <= 20; ++i) { __int128 t = (__int128)fact[i - 1] * i; fact[i] = (unsigned long long)t; // 在范围内,安全 } unsigned long long x; while ( (cin >> x) ) { // 特判 x = 1:没有 >1 的因子,只能是空序列,长度 0,方案数 1 if (x == 1) { cout << 0 << ' ' << 1 << "\n"; continue; } // 分解 x vector<int> exps; // 存放各素因子指数 ai unsigned long long t = x; for (unsigned long long p = 2; p * p <= t; ++p) { if (t % p == 0) { int cnt = 0; while (t % p == 0) { t /= p; ++cnt; } exps.push_back(cnt); } } if (t > 1) exps.push_back(1); // 还剩一个大于 1 的素因子(指数为 1) // 最大长度 L = 所有指数之和 int L = 0; for (int e : exps) L += e; // 方案数 = L! / (a1! * a2! * ... * am!) // 用 128 位中间变量确保中间除法安全(不过这里都能整除) __int128 ways128 = fact[L]; for (int e : exps) { ways128 /= fact[e]; } unsigned long long ways = (unsigned long long)ways128; cout << L << ' ' << ways << "\n"; } return 0; }
- 1
信息
- ID
- 1084
- 时间
- 1000ms
- 内存
- 64MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 0
- 上传者