传送门:点击打开链接
题意:等幂映射是这样定义的,对于一个映射 g : {1,2,...,n} → {1,2,...,n} ,对于所有的 x∈ {1,2,...,n} , g(g(x))=g(x)始终成立。
f(k)(x) 表示将映射f作用于x上k次的结果。一般的, f(1)(x) = f(x), f(k)(x) = f(f(k−1)(x)) 对于所有的k>1成立。
现在给定一个映射 f : {1,2,...,n} → {1,2,...,n} 。你的任务是寻找最小的k使得 f(k)(x) 是一个等幂映射。
样例解释:这个例子中 f(x) = f(1)(x) 已经是一个等幂映射,因为他已经满足定义: f(f(1))=f(1)=1, f(f(2))=f(2)=2, f(f(3))=f(3)=2,f(f(4))=f(4)=4。
思路:这道题是一道很值得去思考的题,这种映射的题都能转换成图论题!
我们考虑建边i->f(i),那么我们可以发现,等幂映射的图中,所有的环的大小只有1,环外面的点距离最近的环的距离也为1
我们现在再来考虑f(f(x))的图相对于f(x)的图会有什么变化。我们能发现,对于节点i,本来i->f(i),然后f(i)->f(f(i)),之后变成了i->f(f(i))
所以每个点连的边是以前连接的点的下一个。
换句话说,f^k(x)就会相当于在以前的图中,对于i新的边的另一端节点v,将是沿着有向边向下走k步,所到达的点。
对于一个环,最后边是可以连到自己身上来的,那么步数必须是环大小的整数倍。
所以,我们找出所有的环的长度,取lcm。
另外还有一个限制,就是非环上的点,必须要通过k步后能到达环上去。所以取完lcm之后,记为ans,如果非环上点到环上的最近距离最大的那个dist,比lcm要大,
就必须要ans+=lcm,直到ans比dist大才行。
#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <stack>
#include <queue>
#include <cstdio>
#include <cctype>
#include <bitset>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
#define fuck(x) cout<<"["<<x<<"]";
#define FIN freopen("input.txt","r",stdin);
#define FOUT freopen("output.txt","w+",stdout);
//#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int MX = 2e2 + 5;
const int INF = 0x3f3f3f3f;
int G[MX][MX], n;
int vis[MX], iscir[MX];
int dp[MX];
vector<int>cir;
int DFS(int u, int dep) {
vis[u] = dep;
int t, ret = 0;
for(int v = 1; v <= n; v++) {
if(!G[u][v]) continue;
if(vis[v] > 0) {
cir.push_back(dep - vis[v] + 1);
iscir[u] = 1; ret = vis[v];
} else if(!vis[v] && (t = DFS(v, dep + 1), t && dep >= t)) {
iscir[u] = 1; ret = t;
}
if(ret) break;
}
vis[u] = -1;
return ret;
}
int DP(int u) {
if(dp[u]) return dp[u];
if(iscir[u]) return 0;
for(int v = 1; v <= n; v++) {
if(!G[u][v]) continue;
dp[u] = max(dp[u], DP(v));
}
return dp[u] += 1;
}
LL gcd(LL a, LL b) {
return b ? gcd(b, a % b) : a;
}
LL lcm(LL a, LL b) {
return a / gcd(a, b) * b;
}
int main() {
//FIN;
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
int x; scanf("%d", &x);
G[i][x] = 1;
}
for(int i = 1; i <= n; i++) {
if(!vis[i]) DFS(i, 1);
}
for(int i = 1; i <= n; i++) vis[i] = 0;
int dist = 0;
for(int i = 1; i <= n; i++) {
dist = max(dist, DP(i));
}
int sz = cir.size();
LL w = 1, ans;
for(int i = 0; i < sz; i++) {
w = lcm(w, cir[i]);
}
for(ans = w; ans < dist; ans += w);
printf("%I64d\n", ans);
return 0;
}