[bzoj1025][SCOI2009]游戏 (分组背包)

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 。

分析

要用到一点点群论的知识:一个置换可以分解成若干个不相交循环的乘积,且这个置换的阶数就等于各个循环的元素个数的最小公倍数。

那么我们要考虑的问题变成了:将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 }

分组背包

时间: 2024-10-08 08:17:33

[bzoj1025][SCOI2009]游戏 (分组背包)的相关文章

BZOJ1025: [SCOI2009]游戏

1025: [SCOI2009]游戏 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 2029  Solved: 1315[Submit][Status][Discuss] Description windy学会了一种游戏.对于1到N这N个数字,都有唯一且不同的1到N的数字与之对应.最开始windy把数字按顺序1,2,3,……,N写一排在纸上.然后再在这一排下面写上它们对应的数字.然后又在新的一排下面写上它们对应的数字.如此反复,直到序列再次变为1,

[BZOJ1025] [SCOI2009]游戏 解题报告

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

bzoj1025: [SCOI2009]游戏(DP)

题目大意:将长度为n的排列作为1,2,3,...,n的置换,有可能置换x次之后,序列又回到了1,2,3,...,n,求所有可能的x的个数. 看见这种一脸懵逼的题第一要务当然是简化题意...我们可以发现,序列回到原状的次数就是每个循环的规模(即在循环中的数字个数)的lcm,而且因为有n个数,显然所有循环的规模之和就是n,那么问题就被简化成了a1+a2+a3+...+ak=n,求lcm(a1,a2,a3,...,an)的个数. 现在题意已经清楚多了,那咋写呢QAQ 我们把一个数分解质因数,p为质数,

bzoj1025 [SCOI2009]游戏——因数DP

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1025 这篇博客写得真好呢:https://www.cnblogs.com/phile/p/4473192.html 代码如下: #include<iostream> #include<cstdio> #include<cstring> using namespace std; int n,pri[1005],cnt; long long f[1005][1005]

BZOJ 1025: [SCOI2009]游戏( 背包dp )

显然题目要求长度为n的置换中各个循环长度的lcm有多少种情况. 判断一个数m是否是满足题意的lcm. m = ∏ piai, 当∑piai ≤ n时是满足题意的. 最简单我们令循环长度分别为piai,不足n的话,我们令其他循环长度为1, 补到=n为止. 这样它们的lcm显然是=m的. 然后就是一个背包了...dp(i, j) = dp(i - 1, j) + ∑1≤t≤adp( i - 1, j - pt ) 表示前i个质数, 和为j有多少中方案 #include<bits/stdc++.h>

SCOI2009游戏

1025: [SCOI2009]游戏 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 1065  Solved: 673[Submit][Status] Description windy学会了一种游戏.对于1到N这N个数字,都有唯一且不同的1到N的数字与之对应.最开始windy把数字按顺序1,2,3,……,N写一排在纸上.然后再在这一排下面写上它们对应的数字.然后又在新的一排下面写上它们对应的数字.如此反复,直到序列再次变为1,2,3,……,N.

HDU 4341 分组背包

B - Gold miner Time Limit:2000MS Memory Limit:32768KB     Description Homelesser likes playing Gold miners in class. He has to pay much attention to the teacher to avoid being noticed. So he always lose the game. After losing many times, he wants you

VijosP1250:分组背包

背景 Wind设计了很多机器人.但是它们都认为自己是最强的,于是,一场比赛开始了~ 描述 机器人们都想知道谁是最勇敢的,于是它们比赛搬运一些物品. 它们到了一个仓库,里面有n个物品,每个物品都有一个价值Pi和重量Wi,但是有些物品放在一起会爆炸,并且爆炸具有传递性.(a和b会爆炸.b和c会爆炸则a和c会爆炸)机器人们可不想因此损失自己好不容易从Wind那里敲诈来的装备,于是它们想知道在能力范围内,它们最多可以拿多少价值的物品. 你能帮助它们吗? 格式 输入格式 每组测试数据第1行为n,Wmax,

HDU-1011 Starship Troopers (树形DP+分组背包)

题目大意:给一棵有根带点权树,并且给出容量.求在不超过容量下的最大权值.前提是选完父节点才能选子节点. 题目分析:树上的分组背包. ps:特判m为0时的情况. 代码如下: # include<iostream> # include<cstdio> # include<vector> # include<cstring> # include<algorithm> using namespace std; const int N=105; const