1025: [SCOI2009]游戏
Time Limit: 1 Sec Memory Limit: 162 MB
Submit: 1573 Solved: 990
[Submit][Status][Discuss]
Description
windy学会了一种游戏。对于1到N这N个数字,都有唯一且不同的1到N的数字与之对应。最开始windy把数字按顺序1,2,3,……,N写一排在纸上。然后再在这一排下面写上它们对应的数字。然后又在新的一排下面写上它们对应的数字。如此反复,直到序列再次变为1,2,3,……,N。 如: 1 2 3 4 5 6 对应的关系为 1->2 2->3 3->1 4->5 5->4 6->6 windy的操作如下 1 2 3 4 5 6 2 3 1 5 4 6 3 1 2 4 5 6 1 2 3 5 4 6 2 3 1 4 5 6 3 1 2 5 4 6 1 2 3 4 5 6 这时,我们就有若干排1到N的排列,上例中有7排。现在windy想知道,对于所有可能的对应关系,有多少种可能的排数。
Input
包含一个整数,N。
Output
包含一个整数,可能的排数。
Sample Input
【输入样例一】
3
【输入样例二】
10
Sample Output
【输出样例一】
3
【输出样例二】
16
HINT
【数据规模和约定】
100%的数据,满足 1 <= N <= 1000 。
Source
题意:给出一个数字n,要你将其分为几个数字,它们的和为n,如a1,a2,a3...ak,并且a1+a2+a3+,....+ak=n,问Lcd(a1,a2,a3,......,ak)有多少种
分析:公倍数可以写成(任意一个数都可以写成)x=p1^d1*p2^d2*.......*pk‘^dk‘,
那么如果Lcd(a1,a2,a3......ak) = x,那么显然p1^d1+p2^d2+......pk‘^dk‘ <= a1+a2+a3+.....+ak = n
这是显然的
那么因为只需要求最小公倍数有多少种,那么显然对于p1^d1+p2^d2+......pk‘^dk‘ = x <n 的情况,只需要将n分解成p1^d1, p2^d2, ...... , pk‘^dk‘ ,以及若干个1即可
那么问题转换成,求若干个质数的阶层相加的和小于等于n的方案数
发现,n<=1000,所以质数最多只有130个左右,这么小的数据量,而且他们的和肯定小于1000,所以背包即可
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <deque> 6 #include <vector> 7 #include <queue> 8 #include <iostream> 9 #include <algorithm> 10 #include <map> 11 #include <set> 12 #include <ctime> 13 using namespace std; 14 typedef long long LL; 15 typedef double DB; 16 #define For(i, s, t) for(int i = (s); i <= (t); i++) 17 #define Ford(i, s, t) for(int i = (s); i >= (t); i--) 18 #define Rep(i, t) for(int i = (0); i < (t); i++) 19 #define Repn(i, t) for(int i = ((t)-1); i >= (0); i--) 20 #define rep(i, x, t) for(int i = (x); i < (t); i++) 21 #define MIT (2147483647) 22 #define INF (1000000001) 23 #define MLL (1000000000000000001LL) 24 #define sz(x) ((int) (x).size()) 25 #define clr(x, y) memset(x, y, sizeof(x)) 26 #define puf push_front 27 #define pub push_back 28 #define pof pop_front 29 #define pob pop_back 30 #define ft first 31 #define sd second 32 #define mk make_pair 33 inline void SetIO(string Name) { 34 string Input = Name+".in", 35 Output = Name+".out"; 36 freopen(Input.c_str(), "r", stdin), 37 freopen(Output.c_str(), "w", stdout); 38 } 39 40 const int N = 1010; 41 int Prime[N], Tot; 42 bool Visit[N]; 43 int n; 44 LL Dp[N][N], Ans; 45 46 inline void Input() { 47 scanf("%d", &n); 48 } 49 50 inline void GetPrime() { 51 Tot = 0; 52 For(i, 2, n) { 53 if(!Visit[i]) Prime[++Tot] = i; 54 For(j, 1, Tot) { 55 if(Prime[j]*i > n) break; 56 Visit[Prime[j]*i] = 1; 57 if(!(i%Prime[j])) break; 58 } 59 } 60 } 61 62 inline void Solve() { 63 GetPrime(); 64 Dp[0][0] = 1; 65 For(i, 1, Tot) { 66 For(j, 0, n) Dp[i][j] = Dp[i-1][j]; 67 for(int x = Prime[i]; x <= n; x *= Prime[i]) 68 For(j, 0, n-x) 69 Dp[i][j+x] += Dp[i-1][j]; 70 } 71 72 For(i, 0, n) Ans += Dp[Tot][i]; 73 cout<<Ans<<endl; 74 } 75 76 int main() { 77 SetIO("1025"); 78 Input(); 79 Solve(); 80 return 0; 81 }