題目鏈接:luogu P4089 / jozj 6661
題目
堅信快樂的牛可以產出更多的牛奶,因此 在牛棚裏安裝了一個巨大的迪斯科球並且打算讓奶牛們學會跳舞。
在許多出名的奶牛舞中選擇了一種叫做 的舞蹈。這種舞蹈由 的 頭奶牛組成。頭奶牛以一種順序排成一行,接着表演數次 。每次的 會將奶牛重新排列。 爲了讓奶牛們更加快樂,讓奶牛們更容易找到重新排列後的位置,他標記了 頭奶牛的位置。在最開始,所有奶牛排成一排,第一頭奶牛會在位置 上,第二隻在 上,以此類推。
我們用 個正整數 ,,,來描述每次的 。說明了在位置 上的奶牛在經過這回合的 之後,會跑到位置 上。令 倍感非洲的是,即使 與 不同,也可能會等於 !所以可能在一次 後,有多頭奶牛會跑到同一位置上,在這之後這羣奶牛也會一同行動。
作爲一名資深的養牛大戶&坑牛專家的 猛然發現,無論經過多少次的 ,一直都有 個位置上有奶牛。現在要你在 秒內幫他得出 的值,否則就賞你 大板!
輸入
第一行包含一個整數,
第二行包含 個整數,描述題目中的 , ,,
輸出
一個整數,代表
樣例輸入
4
3 2 1 3
樣例輸出
3
思路
這道題其實要求出所有環的長度之和。
至於爲什麼,我們把牛的移動方向看做連箭頭,那麼就變成了一個有向圖。
那麼一個環裏面的牛就會不停的交換位置,不會重疊。但是如果有某個點指向了環的某一個地方,這個點的牛就會和環裏面的牛重疊。
所以我們只要找出不在環裏面的點,然後統計出所有環的長度之和就可以了。
代碼
#include<cstdio>
#include<cstring>
using namespace std;
int n, a, to[1000001], ru[1000001], ans;
bool in[1000001], in2[1000001];
void dfs(int now) {
in[now] = 1;
ru[to[now]]--;
if (!ru[to[now]]) dfs(to[now]);
}
int dfs1(int now) {
if (in2[now]) return 0;
in2[now] = 1;
return 1 + dfs1(to[now]);
}
int main() {
// freopen("shuffle.in", "r", stdin);
// freopen("shuffle.out", "w", stdout);
scanf("%d", &n);//讀入
for (int i = 1; i <= n; i++) {
scanf("%d", &a);//讀入
to[i] = a;//連邊
ru[a]++;//記錄入讀數
}
for (int i = 1; i <= n; i++)
if (!ru[i] && !in[i]) dfs(i);//找出不在環內的點
for (int i = 1; i <= n; i++)
if (!in2[i] && !in[i]) ans += dfs1(i);//統計在環中的點的數量
printf("%d", ans);//輸出
// fclose(stdin);
// fclose(stdout);
return 0;
}