Poj 3421-X-factor Chains
来源:互联网 发布:淘宝助理收费吗 编辑:程序博客网 时间:2024/05/23 17:47
Poj 3421-X-factor Chains
题意:给定数x,求一条最长的因子链,1 = X0, X1, X2, …, Xm = X,链中xi<xi+1,且xi整除xi+1,求最长的链的长度和其数量。
因为前段时间要进行考试的预习,每天在自习室呆着,很久没写代码了,好不容易考试完,继续我的刷题之旅,结果一写就gg了…..虽说是个简单题,但是太弱,所以卡了很久,决定纪念一下我谜一般的思路过程…..
1、 刚开始做的时候一眼看上去像个图论题,把x的所有把整除关系看成边,x的因子看成顶点,之后dfs进行图的遍历就行了,找到最长的和其长度,因子稍微多点就基本运行不出结果了,于是进行了一个最优性剪枝,感觉一个数据能很快运行出结果了,直接就交上去,然后超时了,也是无语。
#include <cstdio>#include <algorithm>#include <cstring>#include <cmath>#include <utility>#include <vector>#include <map>using namespace std;map<int, vector<int> > mp;vector<int> d;map<int, int> l;int ans, num;void dfs(int x, int len) { if (len < l[x]) return ; else l[x] = len; if (len >= ans) { if (len == ans) num++; else ans = len, num = 1; } for (int i = 0; i < mp[x].size(); i++) dfs(mp[x][i], len+1);}int main() { int x; while (~scanf("%d", &x)) { d.clear(); mp.clear(); l.clear(); int t = sqrt(x+0.0); d.push_back(1), d.push_back(x); for (int i = 2; i < t; i++) if (x % i == 0) d.push_back(i), d.push_back(x/i); if (t*t == x) d.push_back(t); sort(d.begin(), d.end()); for (int i = 0; i < d.size(); i++) { for (int j = i+1; j < d.size(); j++) if (d[j] % d[i] == 0) mp[d[i]].push_back(d[j]); } ans = 0, num = 1; dfs(d[0], 0); printf("%d %d\n", ans, num); } return 0;}
2、 想来想去,觉得深搜再怎么剪也肯定不行,想了一下dp,对于一个数x,计算两个值,一个是x为最末尾元素的链的最长长度,另一个是这种长度的数量,状态转移为其因子中那些链最长的,然后记忆化搜索的方式实现比较好,跑了一下数据,比之前的深搜快了几十倍,马上高兴地交了上去,还是超时,复杂度已经很低了,这都超时!无奈了,没办法进行优化了,按理来说不应该啊,题目不是说several个test case吗,而且时间限制还有2s,我跑10多个因子数很多的都只要1s左右,其实题目的数据量应该不会只有several个……
#include <cstdio>#include <algorithm>#include <cstring>#include <cmath>#include <utility>#include <vector>#include <map>using namespace std;typedef pair<int, int> p;map<int, vector<int> > mp;map<int, p> l;vector<int> d;p dp(int x) { if (x == 1 || l[x].first) return l[x]; vector<p> vec; for (int i = 0; i < mp[x].size(); i++) vec.push_back(dp(mp[x][i])); int len = vec[0].first, num = vec[0].second; for (int i = 1; i < vec.size(); i++) { if (len < vec[i].first) len = vec[i].first, num = vec[i].second; else if (len == vec[i].first) num += vec[i].second; } return l[x] = p(len+1, num);}int main() { /*freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout);*/ int x; while (~scanf("%d", &x)) { d.clear(); mp.clear(); l.clear(); l[1] = p(0, 1); int t = sqrt(x+0.0); d.push_back(1), d.push_back(x); for (int i = 2; i < t; i++) if (x % i == 0) d.push_back(i), d.push_back(x/i); if (t*t == x) d.push_back(t); sort(d.begin(), d.end()); for (int i = 0; i < d.size(); i++) { for (int j = i+1; j < d.size(); j++) if (d[j] % d[i] == 0) mp[d[j]].push_back(d[i]); } p ans = dp(x); printf("%d %d\n", ans.first, ans.second); } return 0;}
3、 经历了前两次的失败,没什么想法了,只能翻开挑战程序设计实践的数论部分随便看看找点思路了,看到习题练习上那题的标签是素数,于是想到从素数下手,很快就想到了素数筛法,利用筛法的思想进行状态转移,对于一个数x,状态转移至其所有的倍数,紫书上面给出了证明,时间复杂度为O(nlogn),不过转念一想,这样应该比刚刚的复杂度还高啊,写完后交上去果然又超时了…..打算做最后的反抗,看还能不能在优化下,其实在求解答案的过程中,比x小的数的所有数的最长链的长度和数量全部计算出来了,根本不需要每次都O(nlogn)计算一下答案,直接预处理一下所有的数,复杂度也只有O(2^20*20),肯定不会超时,交上去终于过了!!!不过跑了900多ms。
#include <cstdio>#include <algorithm>#include <cstring>using namespace std;const int N = 1048576;typedef pair<int, int> p;p a[N];void predeal() { for (int i = 1; i <= 524288; i++) { for (int j = 2*i; j <= N; j += i) { if (a[i].first + 1 > a[j].first) a[j] = p(a[i].first + 1, a[i].second); else if (a[i].first + 1 == a[j].first) a[j].second += a[i].second; } }}int main() { int x; a[1] = p(0, 1); predeal(); while (~scanf("%d", &x))printf("%d %d\n", a[x].first, a[x].second); return 0;}
4、 最后重新思索一下这个题目,写了一个数模拟下计算的过程,发现了更巧也更简单的思路,其实要使得链尽量长,那么链中的元素前后两个数中大的比小的多一个素因子相乘即可,这样链肯定是最长的,那么数量怎么求呢?其实就是选取素因子相乘的排列问题,这样便转化为了多重集排列数的计算,直接套用离散数学书上的公式即可:
设多重集S={n1*a1,n2*a2,….nk*ak},且n=n1+n2+n3+…+nk,则s的排列数为n!/(n1!*n2!*…nk!)
所以对于一个数x,对其进行唯一分解式的处理,找出所有的素因子和他们的数量。交上去110ms….
#include <cstdio>#include <algorithm>#include <cstring>#include <cmath>#include <map>using namespace std;typedef long long LL;map<int, int> d;void prime_factor(int x) { for (int i = 2; i * i <= x; i++) { while (x % i == 0) x /= i, d[i]++; } if (x != 1) d[x]++;}LL fact(int x) { return x == 1 ? 1 : x * fact(x-1); }int main() { int x; while (~scanf("%d", &x)) { if (x == 1) { printf("0 1\n"); continue; } d.clear(); prime_factor(x); int len = 0; for (map<int, int>::iterator i = d.begin(); i != d.end(); i++) len += i->second; LL num = fact(len); for (map<int, int>::iterator i = d.begin(); i != d.end(); i++) num /= fact(i->second); printf("%d %I64d\n", len, num); } return 0;}
最后重新思索整个过程,还真是感受颇多,一片乱搞,卡了很久才过,从这个简单的数论题中发现了自己数学思维是有多差,不过很多题目都是这样,解题的关键点可以在计算过程中发现或者猜测出来,但是更重要的还是多刷题锻炼这些东西…
- POJ-3421-X-factor Chains
- poj 3421 X-factor Chains
- Poj 3421-X-factor Chains
- POJ 3421 X-factor-Chains
- poj 3421 X-factor Chains
- poj 3421 --X-factor Chains(数学、组合)
- POJ 3421 X-factor Chains 排列组合
- POJ 3421 - X-factor Chains(数学)
- X-factor Chains (poj 3421 数学排列组合)
- poj 3421 X-factor Chains(分解质因数+组合数学)
- POJ 3421 X-factor Chains (约数枚举)
- POJ 3421X-factor Chains【分解质因子+组合数学】
- POJ 3421 X-factor Chains(数论)(筛法)()
- POJ 3421 X-factor Chains 已被翻译
- poj 3421 X-factor Chains(数因子分解)
- poj 3421 X-factor Chains 素数筛选 因子分解
- POJ 3421 X-factor Chains 分解质因数 排列组合
- 码农场 » POJ 3421 X-factor Chains 题解 《挑战程序设计竞赛》
- 欢迎使用CSDN-markdown编辑器
- Java 工程师成神之路
- 安装cocoapods出现的问题(1)
- OC 利用runtime获得类的属性和方法名字
- Pixhawk编译内存溢出
- Poj 3421-X-factor Chains
- Android SQLite 事务处理
- 用文本文件txt来批量新建文件夹(超级实用)
- 数据库索引
- 报表在vista和win7下无法浏览应用的解决办法
- DG部署1
- JAVA并发编程学习笔记之CAS操作
- UTF-8编码格式的Byte Order Mark问题
- 计步器锁屏后依然工作的原理