bzoj 1025[SCOI2009]游戏 - 背包dp

1025: [SCOI2009]游戏

Time Limit: 1 Sec  Memory Limit: 162 MB

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,1 <= N <= 1000

Output

  包含一个整数,可能的排数。

Sample Input

【输入样例一】
3
【输入样例二】
10

Sample Output

【输出样例一】
3
【输出样例二】
16
 
 
很容易发现,每一种对应关系都可以看成几个环,这些环的长度和就是一个N的划分
现在的问题就转化成对于所有N的划分,不同的lcm共有多少种
 
于是进一步转化,因为lcm只由质数的最高次幂决定
而对于任意一个$p1^ {a1} + p2 ^ {a2} + p3 ^ {a3} + ...pi ^ {ai} <= N$
都是一组解
这样我们就可以用 f[i][j] 表示 第i个质数 和为 j 来计算答案了
 
 
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 #include <cstring>
 5 #define LL long long
 6 
 7 using namespace std;
 8 
 9 const int MAXN = 1e3 + 10;
10 int N;
11 int cnt = 0;
12 LL f[MAXN][MAXN];
13 int flag[MAXN];
14 int prime[MAXN];
15 void init()
16 {
17     for(int i = 2; i <= N; i++) {
18         if(!flag[i]) {
19             prime[++cnt] =i;
20         }
21         for(int j = 1; j <= cnt && prime[j] * i <= N; j++) {
22             flag[prime[j] * i] = 1;
23             if(i % prime[j] == 0) {
24                 break;
25             }
26         }
27     }
28 }
29 inline LL read()
30 {
31     LL x = 0, w = 1; char ch = 0;
32     while(ch < '0' || ch > '9') {
33         if(ch == '-') {
34             w = -1;
35         }
36         ch = getchar();
37     }
38     while(ch >= '0' && ch <= '9') {
39         x = x * 10 + ch - '0';
40         ch = getchar();
41     }
42     return x * w;
43 }
44 
45 int main()
46 {
47     N = read();
48     init();
49     f[0][0] = 1;
50     for(int i = 1; i <= cnt; i++) {
51         for(int j = N; j >= 0; j--) {
52             f[i][j] = f[i - 1][j];
53             for(int k = prime[i]; k <= j; k = prime[i] * k) {
54                 f[i][j] += f[i - 1][j - k];
55             }
56         }
57     }
58     LL ans = 0;
59     for(int j = 0; j <= N; j++) {
60         ans += f[cnt][j];
61     }
62     printf("%lld\n", ans);
63     return 0;
64 }
View Code

 

posted @ 2018-02-14 16:12  大财主  阅读(129)  评论(0编辑  收藏  举报