BestCoder7 1001 Little Pony and Permutation(hdu 4985) 解题报告

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4985

题目意思:有 n 个数,对于第 i 个数给出 σ(i) 的值。求出互不相交的循环的个数,并输出每个循环包含的数字。

还是不太懂吧?反正比赛的时候我也没看懂 >__< !

据说,这条题目用到了置换群 + 循环 的知识,黑书上 P246 有相应介绍。

先来说明下这幅图的意思,搞明白题意就发现这条题是很好做的。

它表示:σ(1) = 2, σ(2) = 5, σ(3) = 4, σ(4) = 3, and σ(5) = 1

首先要知道为什么(1 2 5)和(3 4)要划分开来。我们从数字 1 ~ n 遍历,也就是上面的1 2 3 4 5 啦。那么遍历到 1 的时候,可以输出 1 (设一个vis数组,开始时全部为0,输出后vis[1] = 1),接着取σ(1) 也就是 2 啦,发现之前没有输出过(只输出了 1 而已)那就继续输出 2 啦(vis[2] = 1),接着算出σ(2) = 5,输出5(vis[5] = 1),然后发现 σ(5) = 1,但是vis[1] = 1已经输出过,所以不输出了。此时就发现1 2 5 是一个循环,就是说,通过σ(i)计算它只能在1 2 5 中取数。剩下的3 4 也是通过这样算的。

黑书上有一段是这样介绍循环的:

每个置换都可以写成若干互不相交的循环的乘积,两个循环(a1 a2 ...an) 和 (b1 b2 ...bn) 互不相交是指ai≠bj,i,j = 1, 2, ..., n。

例如:

是等于  (1 3 6)(2 5)(4)

因为:1 —> 3 —> 6 —> 1 (循环了),2 —> 5 —> 2(循环了),4 —> 4 (自己循环自己)。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5
 6 const int maxn = 1e5 + 5;
 7 int vis[maxn], a[maxn];
 8
 9 int main()
10 {
11     int n;
12     while (scanf("%d", &n) != EOF)
13     {
14         for (int i = 1; i <= n; i++)
15             scanf("%d", &a[i]);
16         memset(vis, 0, sizeof(vis));
17         for (int i = 1; i <= n; i++)
18         {
19             if (vis[i])
20                 continue;
21             printf("(%d", i);  // 计算一个循环
22             vis[i] = 1;
23             int j = a[i];
24             while (j != i)
25             {
26                 printf(" %d", j);
27                 vis[j] = 1;
28                 j = a[j];
29             }
30             printf(")");
31         }
32         printf("\n");
33     }
34     return 0;
35 }

注意:上面的初始状态默认为 1 2 3 4...n 的

对于一般情况的初始状态(不一定是1 2 3 4...n),给出对应的目标状态,要求分解为不相交的循环乘积的个数。例如初始状态为 8 4 5 3 2 7,而目标状态为 2 3 4 5 7 8,则可以分解为两个循环的乘积,即(8 2 7)(4 3 5).代码如下:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5
 6 const int maxn = 1e5 + 5;
 7 int vis[maxn], a[maxn], b[maxn];
 8
 9 int main()
10 {
11     int n;
12     while (scanf("%d", &n) != EOF)
13     {
14         for (int i = 1; i <= n; i++)
15             scanf("%d", &a[i]);
16         int t;
17         for (int i = 1; i <= n; i++)
18         {
19             scanf("%d", &t);
20             b[a[i]] = t;
21         }
22     /*    for (int i = 1; i <= 8; i++)
23             if (b[i])
24                 printf("b[%d] = %d\n", i, b[i]);
25     */
26         memset(vis, 0, sizeof(vis));
27         for (int i = 1; i <= n; i++)
28         {
29             int k = a[i];
30             if (vis[k])
31                 continue;
32             printf("(%d", k);  // 计算一个循环
33             vis[k] = 1;
34             int j = b[k];
35             while (j != k)
36             {
37                 printf(" %d", j);
38                 vis[j] = 1;
39                 j = b[j];
40             }
41             printf(")");
42         }
43         printf("\n");
44
45     }
46     return 0;
47 }

时间: 2024-10-12 10:49:23

BestCoder7 1001 Little Pony and Permutation(hdu 4985) 解题报告的相关文章

BestCoder18 1001.Alexandra and Prime Numbers(hdu 5108) 解题报告

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5108 题目意思:给出一个数正整数 N,N <= 1e9,现在需要找出一个最少的正整数 M,使得 N/M 是素数.如果找不到就输出0. 一开始有想过将所有 <= 1e9 的素数求出来的,不过绝对超时就放弃了:然后就开始从题目中挖掘简便的处理方法.受到求素数的方法启发,枚举的因子 i 如果在 i * i <= N 之内都没有找到符合条件的素数,那么那些 > N 的因子就更不可能了.于是时间

hdu 2112 HDU Today 解题报告

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2112 题目意思:又是求最短路的,不过结合埋字符串来考查. 受之前1004 Let the Balloon Rise 学到用map 的解法做之后,有点蠢蠢欲动,当时见到要用字典树做有点吓坏了(之前看过下,非一般难理解,所以暂时放下了).于是,死就死吧,硬住头皮用map做,反反复复修改终于过了. 首先是memory limit exceeded,因为无读清题目意思,直接开10000 * 10000的数组

BestCoder7 1002 Little Pony and Alohomora Part I(hdu 4986) 解题报告

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4986 题目意思:有 n 个box(从左到右编号依次为1~n),每个box里面有一个随机的钥匙,有可能这条钥匙恰好可以开到这个box,但大多数情况下是不能够的.问期望值是多少.(例如对于两个box,有可能装着1 2 或者 2 1的 key,如果是1 2,那么就需要用两次咒语,而对于2 1(打开其中一个box就可以得到要开到另一个box的钥匙)只需要用一次即可.期望值就是 1/2 * 2 + 1/2 *

BestCoder10 1001 Revenge of GCD(hdu 5019) 解题报告

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5019 题目意思:给出 X 和 Y,求出 第 K 个 X 和 Y 的最大公约数. 例如8 16,它们的公约数依次为1 2 4 8,那么第 3 个 GCD(X, Y) = 2,也就是从后往前数第3个公共因子. TLE思路:求出 X 的所有因子(从小到大开始存储),再从后往前枚举这些因子,检查是否也为 Y 的因子,统计到第 K 个数就是答案了......以为可以顺利通过,原来数据量还是非常大滴!!! 正确

BestCoder10 1001 Revenge of Fibonacci(hdu 5018) 解题报告

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5018 题目意思:给出在 new Fibonacci 中最先的两个数 A 和 B(也就是f[1] = A, f[2] = B),通过这条式子f[n] = f[n-1] + f[n-2],问 C 是否在这条 new Fibonacci sequence 内.(1 <= A, B, C <= 1 000 000 000) 首先,要想到 C 有可能是 A 或者 B,这种情况也是属于在这个序列范围内的. 还

BestCoder24 1001.Sum Sum Sum(hdu 5150) 解题报告

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5150 题目意思:就是直接求素数. 不过 n = 1,也属于答案范围!!只能说,一失足成千古恨啊----- 1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 using namespace std; 6 7 const int maxn = 1

BestCoder8 1001.Summary(hdu 4989) 解题报告

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4989 题目意思:给出 n 个数,然后将这些数两两相加,得到 n*(n-1) /2 对和,把重复的和去掉,最后相加起来. 用STL中的set可以好方便的做出来,因为 insert 的时候它会自动去除重复的.记得要用 long long 或 int64,因为 -1000000000 <= ai <= 1000000000 ! 1 #include <iostream> 2 #include

BestCoder12 1001.So easy(hdu 5058) 解题报告

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5058 (格式有点问题,为了方便阅读---整个复制下来吧) 题目意思:给出两个长度都为 n 的集合你,问这两个集合是否相等. 其实思路非常容易想到,就是去重后判断嘛---我用到了set 来做.不过有个小细节!!! 1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstr

BestCoder3 1001 Task schedule(hdu 4907) 解题报告

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4907 题目意思:给出工作表上的 n 个任务,第 i 个任务需要 ti 这么长的时间(持续时间是ti ~ ti+1)来完成.有m 个询问,每个询问是一个数字q,表示q 时间上有一个非 n 个任务之外的任务请求.机器是按照工作表的任务时间来执行的,如果有空档时间,它会执行工作表之外的任务请求. 直接做,果断超时!1e5 * 2e5 !!!(m次询问+q次遍历 的最坏情况) 二分解决之----一开始我不是