挑战程序设计竞赛 2.6章习题 poj 3421 X-factor Chains
https://vjudge.net/problem/POJ-3421#author=GPT_zh
Given a positive integer X, an X-factor chain of length m is a sequence of integers,
1 = X0, X1, X2, …, Xm = X
satisfying
Xi < Xi+1 and Xi | Xi+1 where a | b means a perfectly divides into b.
Now we are interested in the maximum length of X-factor chains and the number of chains of such length.
Input
The input consists of several test cases. Each contains a positive integer X (X ≤ 2^20).
Output
For each test case, output the maximum length and the number of such X-factors chains.
2
3
4
10
100
1 1
1 1
2 1
2 2
4 6
给定一个正整数 X,长度为 m 的 X 因子链是一个整数序列,1 = X0, X1, X2, …, Xm = X
满足Xi < Xi+1 且 Xi | Xi+1,其中 a | b 表示 a 完全整除 b。
现在我们对 X 因子链的最大长度和该长度的链的数量感兴趣。
输入
输入包含多个测试用例。每个测试用例包含一个正整数 X (X ≤ 2^20)。
输出
对于每个测试用例,输出最大长度和该长度的 X 因子链的数量。
2
3
4
10
100
1 1
1 1
2 1
2 2
4 6
解答:
一道好题目 可以用多种方案解决
- 分解约数 dp得到最长路径和最长路径数目
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
vector<int> get_divisors(int x)
{
//得到约数 1到 sqrt(x)的整数 逐个尝试是否是约数 时间复杂度 sqrt(x)
vector<int> res;
for (int i = 1; i <= x / i; i++)
if (x % i == 0)
{
res.push_back(i);
if (i != x / i) res.push_back(x / i);
}
//从小到大排列 才好寻找约数链
sort(res.begin(), res.end());
return res;
}
int dp[10000][2];
void solve(const vector<int>& v) {
memset(dp, 0, sizeof dp);
//得到所有质因数后 进行dp得到最长路径和最长路径的数目
dp[0][0] = 0; dp[0][1] = 1;
//dp[x][0]表示第x个约数时 约数链的最大长度
//dp[x][1]表示第x个约数时候,约数链最大长度的数目
for (int i = 1; i < v.size(); i++) {
int vala = v[i];
for (int j = 0; j < i; j++) {
int valb = v[j];
//如果当前数 是之前约数的倍数 那么就查看能组成的最长约数链
if (vala % valb == 0 && dp[j][0] + 1 > dp[i][0]) {
dp[i][0] = dp[j][0] + 1;
dp[i][1] = dp[j][1];
}
else if (vala % valb == 0 && dp[j][0] + 1 == dp[i][0]) {
//如果当前数 是之前约数的倍数 能组成的最长约数链长度不变 最长约数链的个数加1
dp[i][1] += dp[j][1];
}
}
}
//打印答案
cout << dp[v.size() - 1][0] << " " << dp[v.size() - 1][1] << endl;
return;
}
int main()
{
int n;
while (cin >> n) {
vector<int> v = get_divisors(n);
solve(v);
}
return 0;
}
- 分解质因数 dfs获得最长路径的数目
// X-factor Chains POJ - 3421 挑战编程.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <vector>
using namespace std;
vector<int> primes;
void divide(int x)
{
//从2 到 sqrt(x)的整数 逐个尝试
//有质数的因子已经提出 后面在遇到的可约的数 肯定是质因子
//比如 循环将2剔除后 后面的 4 6 8 肯定不会出现 x%4 ==0 ,x%6==0, x%8 ==0
//只可能出现 x%5==0
for (int i = 2; i <= x / i; i++)
if (x % i == 0)
{
int s = 0;
while (x % i == 0) x /= i, s++;
//cout << i << ' ' << s << endl;
primes.push_back(i); primes.push_back(s);
}
if (x > 1) {
//cout << x << ' ' << 1 << endl;
primes.push_back(x); primes.push_back(1);
}
//cout << endl;
}
int ans1 = 0;
long long ans2 = 0;
void dfs(int x) {
if (x >= ans1) {
ans2++;
return;
}
for (int i = 1; i < primes.size(); i += 2) {
if (primes[i] != 0) {
primes[i]--;
dfs(x + 1);
primes[i]++;
}
}
return;
}
int main()
{
int n;
while (cin >> n) {
primes.clear();
divide(n);
ans1 = 0;
// 一个数 2*2*2*3*3 那么它的约数链 最长就是所有质因子都使用的长度。 数目根据素因子排列不同 而有多个
// 2 2*2=4 2*2*2=8 2*2*2*3 = 24 2*2*2*3*3 = 72 约数链长度为5
// 2 2*3 = 6 2*3*3=18 2*3*3*2 = 36 2*3*3*2*2 = 72 约数链长度为5
// 选择所有素因子就是最长路径 = 素因子的幂和
for (int i = 1; i < primes.size(); i+=2) {
ans1 += primes[i];
}
ans2 = 0;
//如上 dfs 遍历质因子的各种不同组合 得到最长链的个数
dfs(0);
cout << ans1 << " " << ans2 << endl;
}
return 0;
}
- 分解质因数 使用排列组合直接得到最长路径数目
#include <iostream>
#include <vector>
using namespace std;
vector<int> primes;
void divide(int x)
{
//从2 到 sqrt(x)的整数 逐个尝试
//有质数的因子已经提出 后面在遇到的可约的数 肯定是质因子
//比如 循环将2剔除后 后面的 4 6 8 肯定不会出现 x%4 ==0 ,x%6==0, x%8 ==0
//只可能出现 x%5==0
for (int i = 2; i <= x / i; i++)
if (x % i == 0)
{
int s = 0;
while (x % i == 0) x /= i, s++;
//cout << i << ' ' << s << endl;
primes.push_back(i); primes.push_back(s);
}
if (x > 1) {
//cout << x << ' ' << 1 << endl;
primes.push_back(x); primes.push_back(1);
}
//cout << endl;
}
long long fac(int x) {
if (x == 1) return 1;
long long ret = 1;
ret *= x*fac(x - 1);
return ret;
}
int main()
{
int n;
while (cin >> n) {
primes.clear();
divide(n);
int ans1 = 0;
// 选择所有素因子就是最长路径
for (int i = 1; i < primes.size(); i+=2) {
ans1 += primes[i];
}
// 一个数 2*2*2*3*3=72 那么它的约数链 最长就是所有质因子都使用的长度。 数目根据素因子排列不同 而有多个
// 2 2*2=4 2*2*2=8 2*2*2*3 = 24 2*2*2*3*3 = 72 约数链长度为5
// 2 2*3 = 6 2*3*3=18 2*3*3*2 = 36 2*3*3*2*2 = 72 约数链长度为5
// 素因子的所有幂和的阶乘就是所有约数路径的组合
// 除以每个素因数的阶乘 也就是取出重复的排列组合
// 最后就是选取所有素因数(最长路径) 的路径数目
//比如一个数 2*2*2*3*3=72 有三个2 两个3排列组合 所以有5!选择
//考虑到某位的选择, 选择第一个2 和第二个2 是重复的, 那么5!/(2!*3!) 就是答案 就是选取所有素因数(最长路径) 的路径数目
long long ans2 = fac(ans1); //数据范围2^20 最多20! long long 即可
for (int i = 1; i < primes.size(); i+= 2) {
ans2 = ans2 / fac(primes[i]);
}
cout << ans1 << " " << ans2 << endl;
}
return 0;
}
作 者: itdef
欢迎转帖 请保持文本完整并注明出处
技术博客 http://www.cnblogs.com/itdef/
B站算法视频题解
https://space.bilibili.com/18508846
qq 151435887
gitee https://gitee.com/def/
欢迎c c++ 算法爱好者 windows驱动爱好者 服务器程序员沟通交流
如果觉得不错,欢迎点赞,你的鼓励就是我的动力
欢迎转帖 请保持文本完整并注明出处
技术博客 http://www.cnblogs.com/itdef/
B站算法视频题解
https://space.bilibili.com/18508846
qq 151435887
gitee https://gitee.com/def/
欢迎c c++ 算法爱好者 windows驱动爱好者 服务器程序员沟通交流
如果觉得不错,欢迎点赞,你的鼓励就是我的动力


【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话