본문 바로가기
개인 공부/알고리즘 트레이닝

[C언어/BOJ] BOJ 2526 싸이클

by 아메리카노와떡볶이 2020. 6. 4.
728x90

https://www.acmicpc.net/problem/2526

 

2526번: 싸이클

두 자연수 N과 P를 가지고  다음 과정을 거쳐서 나오는 숫자들을 차례대로 출력해보자. 처음 출력하는 숫자는 N이고, 두 번째 이후 출력하는  숫자들은 N을 곱하고 P로 나눈 나머지를 구하는 과��

www.acmicpc.net

문제

두 자연수 N과 P를 가지고  다음 과정을 거쳐서 나오는 숫자들을 차례대로 출력해보자. 처음 출력하는 숫자는 N이고, 두 번째 이후 출력하는  숫자들은 N을 곱하고 P로 나눈 나머지를 구하는 과정을 반복하여 구한다. 즉, 먼저 N에 N을 곱하고, 이 수를 P로 나눈 나머지를 두 번째에 출력한다. 다음에는 이 나머지에 N을 곱하고 P로 나눈 나머지를 출력한다. 다음에는 이 나머지에 N을 곱한 후 P로 나눈 나머지를 출력한다. 이 과정을 계속 반복해보면 출력되는 숫자들에는 반복되는 부분이 있다. 

예를 들어서, N=67, P=31인 경우를 생각해보자. 처음 출력되는 숫자는 67이고, 두 번째로 출력되는 숫자는 67*67 = 4489를 31로 나눈 나머지 25이다. 다음에는 25*67 = 1675를 31로 나눈 나머지 1, 다음에는 1*67 = 67을 31로 나눈 나머지 5가 차례대로 출력된다. 다음에는 5*67 = 335를 31로 나눈 나머지 25가 출력되는데, 이 수는 이미 이전에 출력된 수이다. 이 과정을 그림으로 보이면 다음과 같다.

즉 이 과정을 반복하면, 처음 67을 제외하면 3개의 숫자 25, 1, 5가 계속 무한히 반복되게 된다.   또 다른 예로, N=9, P=3을 가지고 시작하면, 9*9 = 81이고 3으로 나눈 나머지는 0이며, 0*3 = 0이고 3으로 나눈 나머지도 0이기 때문에 처음 9를 제외하면 0이 무한히 반복되게 된다. 

N과 P를 입력받아 위와 같이 정의된 연산을 수행하였을 때,  반복되는 부분에 포함된 서로 다른 숫자의 개수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 처음 시작하는  N과 P가 공백을 사이에 두고 주어진다. 단, 1<=N<=1,000, 2<=P<=97이다.  

출력

첫째 줄에 반복되는 부분에 포함된 서로 다른 숫자의 개수를 출력한다.

 

 

풀이

처음 이 문제를 접했을때 예제에서 보여준대로 중복되는 값이 존재할때, 그때까지 나왔던 모든 수들이 반복되는 것이라고 생각했습니다. 하지만 그렇게 풀이하면 반례가 존재했습니다.

예를 들면 3개의 숫자  8 25 33이 반복된다고 할때, 그 반복패턴은 반드시 초기값 -> 8 ->25 -> 33 ->8 -> 25 ->33 과 같은 패턴이 아니라, 1 -> 5 -> 3 -> 8 -> 25-> 33 ->8 ->25 ->33 등으로 나타날수도 있습니다.

따라서 접근방식을 바꾸어야합니다. 위의 예시에서 얻어낼수있는 힌트는

8이 반복돼서 출현했을때의 인덱스에서 그 앞에 1,5,3 에서 쓰인 3가지 경우를 빼야한다는 것입니다.

 

#pragma warning(disable:4996)
#include <stdio.h>

int main() {
    int N, P;
    scanf("%d %d", &N, &P);
    int cycle[1000] = { 0 };
    int c = 0;
    int a = 0,b=0;
    int same_cnt = 0;
    cycle[0] = N;
    while (1) {
        if (same_cnt >= 1) break;
        c++;
        if (c == 1) {
            a = N * N % P;
            cycle[c] = a;
        }
        else {
            b = (a *N) % P;

            a = b;
            cycle[c] = a;
        }
      
        for (int p = 0; p < c; p++) {
            if (cycle[c] == cycle[p]) { // 중복된게 출현한다면
                printf("%d", c- p);  // p인덱스에서 c인덱스를 빼주어서 앞에 규칙이 아닌데 등장한 카운트를 뺍니다.
                same_cnt++;
                break;
            }
        }
        
    }
    return 0;
}

728x90

댓글