코딩/백준 문제 풀이

BOJ 2924 - 천재

stonejjun 2020. 8. 17. 15:59

문제 링크 : https://www.acmicpc.net/problem/2924

문제 풀이

주어진 수열의 i번째 값을 A[i]라고 하자. 우리는 $C\leq k\leq N-D$ 인 k들에 대해서 모든 A[A[A[A[A[...A[k].]]]]=k가 되는 최소 횟수를 찾아야 한다. 당연히 B번을 돌려보는 것은 문제를 해결할 수 있는 방법이 아니다. 최소 횟수를 m이라고 하면 답은 (B회까지 처음과 같은 형태의 개수 - A-1회 까지 처음과 같은 형태의 개수) 이기 때문에 (b+m-1)/m-(a+m-2)/m의 형태가 된다. 따라서 m을 구하기만 하면 된다. 

각 k에 대해서 다시 k로 돌아오는데 까지 걸리는 횟수를 알게 되면 $C\leq k\leq N-D$ 인 k들에 대해서 그 횟수들을 모두 lcm 취해주면 모든 k가 원상태로 돌아온 문제에서 원하는 조건이 되기까지 걸리는 횟수를 알 수 있게 된다. 

이 문제를 그래프 문제로 바꿔서 해결할 것이다. 1번부터 N번까지 N개의 노드가 있다고 가정하고 A[i]=j 라는 것은 i->j의 간선이 존재한다는 것이다. j는 모두 1번씩 등장하기 때문에 전체 그래프는 사이클들로만 이루어져 있게 된다. 따라서 각 k가 크기 몇짜리의 사이클에 속해있는지만 알면 된다. 이는 간선을 이어주는 것 대신에 union 시켜줌으로써 그룹의 크기를 통해 알 수 있다.

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
 
ll par[1010101];
ll siz[1010101];
 
ll fi(ll x){
    if(x==par[x]) return x;
    return par[x]=fi(par[x]);
}
 
void uf(ll a,ll b){
    a=fi(a);
    b=fi(b);
    if(a==b) return ;
 
    par[a]=b;
    siz[b]+=siz[a];
}
 
ll arr[1010101];
 
 
int main(){
    ll i,j,k,l,m,n,a,b,c,d;
    scanf("%lld %lld %lld %lld %lld",&n,&a,&b,&c,&d);
    for(i=1;i<=n;i++){
        scanf("%lld",&arr[i]);
        siz[i]=1;
        par[i]=i;
    }
    for(i=1;i<=n;i++){
        uf(i,arr[i]);
    }
    ll alcd=1;
    for(i=1+c;i<=n-d;i++){
        alcd=alcd*siz[fi(i)]/__gcd(alcd,siz[fi(i)]);
    }
    printf("%lld\n",(b+alcd-1)/alcd-(a+alcd-2)/alcd);
}

'코딩 > 백준 문제 풀이' 카테고리의 다른 글

BOJ 1028 - 다이아몬드 광산  (0) 2020.08.18
BOJ 17834 - 사자와 토끼  (0) 2020.08.17
BOJ 15907 - Acka의 리듬 세상  (0) 2020.08.06
BOJ 15311 - 약팔기  (2) 2020.08.03
BOJ 1395 - 스위치  (0) 2020.07.27