bzoj1025 [SCOI2009]游戏

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 }
View Code

 

posted @ 2015-08-29 11:54  yanzx6  阅读(137)  评论(0编辑  收藏  举报