bzoj 1025[SCOI2009]游戏 - 背包dp
1025: [SCOI2009]游戏
Time Limit: 1 Sec Memory Limit: 162 MBDescription
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
3
【输入样例二】
10
Sample Output
【输出样例一】
3
【输出样例二】
16
3
【输出样例二】
16
很容易发现,每一种对应关系都可以看成几个环,这些环的长度和就是一个N的划分
现在的问题就转化成对于所有N的划分,不同的lcm共有多少种
于是进一步转化,因为lcm只由质数的最高次幂决定
而对于任意一个$p1^ {a1} + p2 ^ {a2} + p3 ^ {a3} + ...pi ^ {ai} <= N$
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 }