Codeforces 741A:Arpa's loud Owf and Mehrdad's evil plan(LCM+思维)

http://codeforces.com/problemset/problem/741/A

题意:有N个人,第 i 个人有一个 a[i],意味着第 i 个人可以打电话给第 a[i] 个人,所以如果第 i 个人打电话出去,那么序列是 a[i], a[a[i]], a[a[a[i]]]……,打了 t 次电话后终点为y,那么从 y 也要打 t 次电话之后终点为 i,问最少要打多少次电话才能让所有人满足这样的条件。不存在输出 -1.

思路:这样的一个个序列就是一个环,因为要让所有人满足这个条件,所以 x * m = t , x 是每一个环节自身的长度, m 是一个整数, t 是最后的答案,那么求出所有环的最小公倍数,就是最后的答案了。如果环的长度为偶数,那么存在着一个 y 可以使得 x 能打电话给 y 的同时, y 也能打电话给 x,所以这样长度可以除以2。判断存不存在的话,只有每一个点的入度都不为 0,它才有可能形成环,否则会不能形成环。

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <cstring>
 5 #include <string>
 6 #include <cmath>
 7 #include <queue>
 8 #include <vector>
 9 using namespace std;
10 #define INF 0x3f3f3f3f
11 #define N 100010
12 typedef long long LL;
13 int deg[110];
14 int a[110];
15 
16 LL solve(int n) {
17     LL ans = 1;
18     memset(deg, 0, sizeof(deg));
19     for(int i = 1; i <= n; i++) {
20         if(deg[i] == 0) { // 经过的点的路径形成一个环
21             LL tmp = 1;
22             int x = a[i];
23             deg[i] = 1;
24             while(!deg[x]) {
25                 deg[x] = 1;
26                 x = a[x];
27                 tmp++;
28             }
29             ans = ans / __gcd(ans, tmp) * tmp;
30         }
31     }
32     if(!(ans & 1)) ans /= 2;
33     return ans;
34 }
35 
36 int main()
37 {
38     int n;
39     scanf("%d", &n);
40     for(int i = 1; i <= n; i++) {
41         scanf("%d", a+i);
42         deg[a[i]]++;
43     }
44     bool flag = true;
45     for(int i = 1; i <= n; i++) {
46         if(!deg[i]) {
47             flag = false;
48             break;
49         }
50     }
51     if(!flag) puts("-1");
52     else printf("%I64d
", solve(n));
53     return 0;
54 }
原文地址:https://www.cnblogs.com/fightfordream/p/6140841.html