数论+DP HDOJ 4345 Permutation
2015-08-28 10:17
260 查看
题目传送门
题意:一个置换群,经过最少k次置换后还原。问给一个N个元素,在所有的置换群里,有多少个不同的k。
分析:这道题可以转化成:N = Σ ai ,求LCM ( ai )有多少个不同的值。比如N=10时,k可为:1,2,3,2*2,5,2*3,7,2*2*2,3*3,2*5,2*2*3,2*7,3*5,2*2*5,3*7,2*3*5,共16个,这里用到了唯一分解定理:每个大于1的自然数均可写为质数的积,而且这些素因子按大小排列之后,写法仅有一种方式。例如:
。那么先预处理出1000内的素数,dp[i][j]表示用到了前i个素数,组成和为j,的个数,一个素数可能用到多次。因为1对结果不影响,所以结果是Σ dp[m][i] (m最大的素数<=n,i<=n)
收获:1. 置换群和唯一分解定理 2. DP和数论结合
代码:
题意:一个置换群,经过最少k次置换后还原。问给一个N个元素,在所有的置换群里,有多少个不同的k。
分析:这道题可以转化成:N = Σ ai ,求LCM ( ai )有多少个不同的值。比如N=10时,k可为:1,2,3,2*2,5,2*3,7,2*2*2,3*3,2*5,2*2*3,2*7,3*5,2*2*5,3*7,2*3*5,共16个,这里用到了唯一分解定理:每个大于1的自然数均可写为质数的积,而且这些素因子按大小排列之后,写法仅有一种方式。例如:
。那么先预处理出1000内的素数,dp[i][j]表示用到了前i个素数,组成和为j,的个数,一个素数可能用到多次。因为1对结果不影响,所以结果是Σ dp[m][i] (m最大的素数<=n,i<=n)
收获:1. 置换群和唯一分解定理 2. DP和数论结合
代码:
/************************************************ * Author :Running_Time * Created Time :2015-8-27 18:11:40 * File Name :F.cpp ************************************************/ #include <cstdio> #include <algorithm> #include <iostream> #include <sstream> #include <cstring> #include <cmath> #include <string> #include <vector> #include <queue> #include <deque> #include <stack> #include <list> #include <map> #include <set> #include <bitset> #include <cstdlib> #include <ctime> using namespace std; #define lson l, mid, rt << 1 #define rson mid + 1, r, rt << 1 | 1 typedef long long ll; const int N = 1e3 + 10; const int INF = 0x3f3f3f3f; const int MOD = 1e9 + 7; int prime[N/2]; bool is_prime ; ll dp[200] ; int seive(void) { int p = 0; memset (is_prime, true, sizeof (is_prime)); for (int i=2; i<=1000; ++i) { if (is_prime[i]) prime[++p] = i; for (int j=1; j<=p && prime[j]*i<=1000; ++j) { is_prime[i*prime[j]] = false; if (i % prime[j] == 0) break; } } return p; } int main(void) { int p = seive (); int n, m = 0; while (scanf ("%d", &n) == 1) { memset (dp, 0, sizeof (dp)); dp[0][0] = 1; for (int i=1; i<=p; ++i) { for (int j=0; j<=n; ++j) dp[i][j] = dp[i-1][j]; int res = prime[i]; if (res <= n) m = i; else break; while (res <= n) { for (int j=0; j+res<=n; ++j) { if (dp[i-1][j]) dp[i][j+res] += dp[i-1][j]; } res *= prime[i]; } } ll ans = 0; for (int i=1; i<=n; ++i) ans += dp[m][i]; printf ("%I64d\n", ans + 1); } return 0; }
相关文章推荐
- rsyslog
- [数据结构]字符串匹配KMP
- MySQL存储引擎MyISAM与InnoDB的区别
- 文章标题
- Linux学习笔记-----Linux服务管理----讲12.1 Linux服务管理-----服务分类
- iOS 后台播放音乐
- finally 中最好不要有return
- 队列
- 图片延时 加载原理 及应用
- Sublime Text3 支持中文、ASCII编码的插件
- awk 正则表达式、正则运算符详细介绍(转)
- 技术文摘6 行业 戒指 白银
- Android SDK体系简析
- git技巧
- WPF中嵌入普通Win32程序的方法
- Q_OBJECT宏的作用
- MediaInfo参数大全
- hdu1163 Eddy's digital Roots
- CF 163 A Substring and Subsequence(dp)
- 利用python数组解析ifconfig命令输出