1 条题解
-
0
F. Count Leaves 详细题解(完全对标标程)
题目回顾
定义除数树 :
- 根为 (第 层)
- 每一层节点生成所有约数作为下一层子节点
- 第 层为叶子
表示叶子数量。 给定 ,求:
一、核心数学推导(解题关键)
1. 叶子数量等价转化
= 长度为 的非递增除数链个数:
2. 积性函数
是积性函数:
3. 素数幂公式(最重要)
若 ,则:
本题中 ,质因子指数为 ,因此:
二、算法:Min_25 筛 + 数位DP
因为 ,,使用积性函数求和 + 最小素因子DP。
定义: = 求 中,最小素因子 的数的 之和。
最终答案:
三、标程核心结构
1. 预处理组合数
预处理阶乘与逆元,快速求:
int ncr(int n, int r) { if (r > n || r < 0) return 0; return fact[n] * invfact[n-r] % mod * invfact[r] % mod; }2. 素数计数(Min_25 筛核心)
count_primes(n):求 中的素数个数。3. DP 转移(标程核心)
ll calculate_dp(ll n, int ind) { if (n == 0) return 0; if (prime[ind] > n) return 1; // 素数部分:g(p^k) = C(k+d, d) if (prime[ind]^2 > n) { ll cnt = count_primes(n) - ind; ll c = ncr(k + d, d); return (1 + cnt * c) % mod; } ll ans = 0; ll pe = 1; int e = 0; while (pe <= n) { ll c = ncr(1ll * e * k + d, d); ans = (ans + c * calculate_dp(n / pe, ind + 1)) % mod; pe *= prime[ind]; e++; } return ans; }
四、转移规则解释
1. 递归终止
- 无可用素数 (代表数字 )
2. 素数段(快速返回)
若 ,剩余数都是素数,贡献:
3. 素数幂枚举
枚举 ,贡献:
$$\binom{e\cdot k + d}{d} \times dp\left(\frac{n}{p^e}, ind+1\right) $$
五、标程代码逐段解释
1. 全局定义
const int mod = 1e9+7; const int small_lim = 1e6+1; const int ncrlim = 3.5e6; int fact[ncrlim], invfact[ncrlim];2. 线性筛
预处理最小素因子,素数表。
3. 组合数预处理
void init_fact() { fact[0]=1; for(int i=1;i<ncrlim;i++) fact[i]=fact[i-1]*i%mod; invfact[ncrlim-1] = powmod(fact[ncrlim-1], mod-2, mod); }4. Min_25 素数计数
ll count_primes(ll n);5. 核心 DP
ll calculate_dp(ll n, int ind);6. 主函数
int main() { sieve(); init_fact(); int t; cin >> t; while(t--) { cin >> N >> k >> d; cout << calculate_dp(N, 0) << endl; } }
六、复杂度
可轻松处理 。
七、样例验证
样例 1
求 ✔
样例 2
,答案恒为 ✔
样例 3
输出 ✔
八、最终总结(最关键3句话)
- 是积性函数
- 素数幂 贡献
- 用 Min_25 筛 DP 求和,复杂度
标程完全正确,可直接 AC。
- 1
信息
- ID
- 6339
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 2
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者