【DP例题选讲】&因式分解问题-任何人都不适合放弃&
来源:互联网 发布:关于sql查询的实训报告 编辑:程序博客网 时间:2024/04/30 04:57
DP选讲-因式分解问题
- DP选讲-因式分解问题
- 写在前面
- 题目讲解TIME
- 题目描述
- DFS-原地瞬间爆炸TLE
- DFS优化-然而并没有什么不同
- 部分记忆化-论怎么骗部分分值
- 正确的DP存储方式
- 最快-最正-最真的最优代码
- 小结
- END-OF-ALL
写在前面
掐指一算,因式分解问题应该是我思考时长最久的一道题。坦白来说,自从我踏进算法这一新世界的大门开始【就是搜索啦】,这一梦魇就一直盘旋在上方,让我十分的不快、愤怒、无奈。
但这没关系,我靠着自己坚定的步伐,一步一步的,将这道题斩在了前进的道路上,狠狠地。我并没有借助外部的力量:像是正解博客、或是已做出的同学。
我靠着自己的力量。我坚信:我可以做到。
尽管不是最优算法,但是,写写博客让大家知道我的心路历程,也挺好。
题目讲解TIME
题目描述
将大于1的自然数N进行因式分解,满足 N=a1*a2*……*am 编一个程序,对任意的自然数N,求N的所有形式不同的因式分解方案总数。
例如,N=12,共有8种分解方案,分别是:
输入
第1行:1个正整数N(N<=10^9)
输出
第1行:一个整数,表示N的因式分解方案总数
样例输入
12
样例输出
8
DFS-原地瞬间爆炸TLE
第一反应:构造所有方案数。
实现过程很简单:枚举2~n内n的因子i,将它放在当前一位上,递归枚举n/i。
想想当初的自己也是天真,居然天真地以为这样的算法非常高大上,然后用高大上的写法写出来后发现并不是那样的。
而是这样的:
“输入
“等待一秒……”
“等待两秒……”
“等待三秒……”
“栈溢出警告”
“程序关闭”
“内心OS:(╯‵□′)╯︵┻━┻”
DFS果然是很万能……地超时。
int dfs(int n){ int k=0; if(n==1) return 1; for(int i=n;i>=2;i--) { if(n%i) continue; k+=dfs(n/i); } return k;}//错误的示范方法
DFS优化-然而并没有什么不同
枚举因子的时候,其实然可以枚举
然而:如果算法本身出了问题,即使把这个算法优化到了极致,依然无用。
int dfs(int n){ int k=1; if(n==1) return 1; for(int i=n/2;i>=sqrt(n);i--) { if(n%i) continue; if(n/i!=i) k+=dfs(n/i);//不要忘考虑平方根 k+=dfs(i); } return k;}//并无什么用的莫名之优化
部分记忆化-论怎么骗部分分值
学到DP时,再次看到了这道题,于是想到记忆化。
然而……然而更尬的问题出现了,
于是聪明的我出了一记十分的机制的招式【明明是损招】:只开一部分记忆化;另一部分如果超出了某个界限MAXN,就只能重复算咯。
啊哈哈我真是骗分达人【然而并没有AC(〃>皿<)】
const int MAXN=1000000;int f[MAXN+5];int Function(int x){ if( x <= MAXN && f[x] != 0) return f[x]; int res=1; for(int i=x/2;i>=sqrt(x);i--) { if(x%i) continue; if(x/i!=i) res+=Function(x/i);//不要忘考虑平方根 res+=Function(i); } if( x <= MAXN ) f[x]=res; return res;}//骗分专用:部分记忆化
正确的DP存储方式
通过观察估算,我们其实发现:状态存储并不需要那么多。比方说:对于当前这个数据而言,如果它是奇数,那么所有2的倍数的状态是闲置着的,就会产生白白浪费了很多空间的情况。所以为了保证状态的高效存储——诸君,我有一个大胆的想法:
使用动态数组vector存储,映射表map找到状态是否存在过
那么,掌声欢迎AC代码!
map<int,int>m;vector<long long>f;long long Function(int x){ if(x==1) return 0; if( m.count(x) ) return f[m[x]]; long long res=1; for(int i=2;i<=sqrt(x);i++) if( x % i == 0) res+=Function(i); for(int i=sqrt(x);i>=2;i--) if( x % i == 0 && i != sqrt(x) ) res+=Function(x/i); m[x]=f.size(); f.push_back(res); return res;}
最快-最正-最真的最优代码
总觉得用动态数组有些别扭
那,可不可以在没有DP之前就找到所有合法且可利用的状态呢?
答案是:显然可以
从状态转移方程来讲,一个数的转移是由它的因数转移而来的。
而它的因数是由它的因数的因数转移而来的,总而言之也是它的因数
所以,我们为何不妨先预处理n的因数,再进行愉快地动规?
int f[10005],g[10005],len;void Find_Prime(int x){ f[len]=1; for(int i=2;i<=sqrt(x);i++) if( x % i == 0) f[++len]=i; for(int i=len;i>=1;i--) if( f[i]*f[i]!=x ) f[++len]=x/f[i]; f[++len]=x;}//寻找n的因数int Function(int x)//处理的是n的第x个因数{ if(g[x]) return g[x]; for(int i=1;i<=x;i++) if( f[x] % f[i] == 0 ) g[x]+=Function(lower_bound(f,f+len+1,f[x]/f[i])-f);//因为因数序列是单调递增的,所以可以使用二分查找 return g[x];}...printf("%d",Function(len));
小结
如果说,人不遇到点什么困难,是不现实的
人总会遇到形形色色的难处,编程也是,因为我们并非圣贤,并非“生而知之者”
但是,如果遇到一点困难就退缩,遇到一道难题就四处查正解,如果不会自己动脑想问题,不去自己动脑想问题
那样的话,怎么会有自己攻克题目的自豪感?怎么不会充斥“一看题解就懂,然而自己想不出来的尴尬?”
正如标题所言:
你,我,在世界上的任何人
都不适合放弃
END-OF-ALL
就是这样,新的一天里,也请多多关照哦(ノω<。)ノ))☆.。~
- 【DP例题选讲】&因式分解问题-任何人都不适合放弃&
- 任何人都可以成功
- 任何人都可以重构
- 任何人都可以重构
- 数位DP 小讲 【 理解 + 例题 】 更新 ing......
- 树状DP 小讲 【 理解 + 例题 】 更新 ing......
- 网络流例题及构图选讲
- 【每日算法】链表 & 例题选讲
- dp例题
- DudaMobile:任何人都可以DIY移动网站
- 《跟任何人都聊得来》读书笔记
- 任何人都能看懂的TensorFlow介绍
- 跟任何人都聊得来
- 阶乘因式分解问题
- 问题 E: 因式分解
- godaddy不适合部署asp。net网站,果断放弃!
- DP学习 经典例题 三角形最佳路径问题(NOI7625)
- 群聊真的不适合讨论问题
- Mybatis基于接口代理的方式来开发Dao(二)
- 171001 逆向-Reversing.kr(WindowsKernel)
- 10-1NOIP模拟赛总结
- LintCode链表求和221
- static关键字
- 【DP例题选讲】&因式分解问题-任何人都不适合放弃&
- PAT 甲级 1063. Set Similarity (25)
- 洛谷题目按难度点评---普及
- Q05现金支付
- VMware Host Only方式联网配置注意
- Q06考拉兹猜想
- ArcGIS 10.0紧凑型切片读写方法
- LeetCode Exercise 3: Longest Substring Without Repeating Characters
- java开发中常用到的快捷键