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
Output
Sample Input
Sample Output
HINT
【数据规模和约定】
100%的数据,满足 1 <= N <= 1000 。
分析
要用到一点点群论的知识:一个置换可以分解成若干个不相交循环的乘积,且这个置换的阶数就等于各个循环的元素个数的最小公倍数。
那么我们要考虑的问题变成了:将N划分成若干个整数的和,这些整数的最小公倍数共有多少种取值?
先考虑一个整数的唯一分解$M=\prod {p_i} ^ {a_i}$,如果它在答案中,则$S = \sum {p_i} ^ {a_i}$一定在N以内。因为对于一个不大于N的整数的任何一个满足最大公约数大于1的整数划分,我们将每个整数中重复的质因子除去,得到的一组两两互质的整数,它们的和也一定不大于N,且它们的最小公倍数不变。因此我们只需计算出N以内这些两两互质的整数划分的方案树就可以了。简单来说,就是“要用一个整数划分凑出某个确定的最小公倍数,最‘节约’的方案是用这个最小公倍数的唯一分解”。
具体地,我们可以先筛出N以内的所有素数,对于每种素数只能选择其中的一个幂次乘入答案,求一下分组背包就可以了。
1 /* ************************************************************* 2 Problem: 1025 3 User: AsmDef 4 Language: C++ 5 Result: Accepted 6 Time:4 ms 7 Memory:824 kb 8 *************************************************************** */ 9 10 /* ********************************************************************* */ 11 /* *********************By Asm.Def-Wu Jiaxin**************************** */ 12 /* ********************************************************************* */ 13 #include <cstdio>
14 #include <cstring>
15 #include <cstdlib>
16 #include <ctime>
17 #include <cctype>
18 #include <algorithm>
19 #include <cmath>
20 using namespace std;
21 typedef
long long LL;
22 #define SetFile(x) ( freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout) )
23 #define getc() getchar()
24 template<
class T>inline
void getd(T &x){
25 char ch = getc();
bool neg =
false;
26 while(!isdigit(ch) && ch !=
' - ')ch = getc();
27 if(ch ==
' - ')ch = getc(), neg =
true;
28 x = ch -
' 0 ';
29 while(isdigit(ch = getc()))x = x *
10 -
' 0 ' + ch;
30 if(neg)x = -x;
31 }
32 inline
void putLL(LL x){
33 if(x <
1000000000){printf(
" %d\n ", x);
return;}
34 int l = x /
1000000000, r = x %
1000000000;
35 printf(
" %d%09d\n ", l, r);
36 }
37 /* ********************************************************************* */ 38 const int maxn =
1010;
39 int prime[maxn], pcnt, N;
40 LL F[maxn], tmp[maxn];
41 inline
void euler(){
42 bool not_p[maxn] = {
0};
43 int i, j;
44 for(i =
2;i <= N;++i){
45 if(!not_p[i])prime[++pcnt] = i;
46 for(j =
1;j <= pcnt;++j){
47 if(i * prime[j] > N)
break;
48 not_p[i * prime[j]] =
true;
49 if(i % prime[j] ==
0)
break;
50 }
51 }
52 }
53 54 inline
void work(){
55 getd(N);
56 euler();
57 // for(int i = 1;i <= pcnt;++i)printf("%d\n", prime[i]); 58 int i, j, p, d;
59 LL ans =
1;
60 F[
0] =
1;
61 for(i =
1;i <= pcnt;++i){
62 p = prime[i];
63 memcpy(tmp, F,
sizeof(F));
64 for(d = p;d <= N;d *= p)
65 for(j = d;j <= N;++j)F[j] += tmp[j-d];
66 }
67 for(i =
1;i <= N;++i) ans += F[i];
68 putLL(ans);
69 }
70 71 int main(){
72 73 #ifdef DEBUG
74 freopen(
" test.txt ",
" r ", stdin);
75 #elif !defined ONLINE_JUDGE
76 // SetFile(bzoj_1025); 77 #endif 78 work();
79 80 #ifdef DEBUG
81 // printf("\n%.2lf sec \n", (double)clock() / CLOCKS_PER_SEC); 82 #endif 83 return 0;
84 }
分组背包