문제출처: https://www.acmicpc.net/problem/1676


풀이

도대체 어떻게 풀 수 있는 문제일까 고민을 많이 했는데 딱히 떠오르지 않아서 구글링을 통해 10은 2*5으로 이루어진다는 힌트만 얻고 대충 1!부터 10!부터 노트에 적어보며 규칙성을 찾아보았습니다. (사실 위의 힌트가 정답의 전부입니다.)


1!= 1*1

2!= 2*1

3!= 3*2*1

4!= 4*3*2*1

5!= 5*4*3*2*1

6!= 6*5*4*3*2*1

7!= 7*6*5*4*3*2*1

8!= 8*7*6*5*4*3*2*1

9!= 9*8*7*6*5*4*3*2*1

10!= 10* 9*8*7*6*5*4*3*2*1


이렇게 펼쳐본다음 위에서 얻은 힌트를 이용해서 팩토리얼을 구성하는 숫자들을 2와 5로 쪼개어 보았습니다. 그리고 쪼갠 숫자들을 나열하여 2와 5가 각각 몇번 나오는 지를 세어보았습니다.


2!= 2*1 => 2: 1개, 5: 0개

3!= 3*2*1 => 2: 1개, 5: 0개

4!= 2*2*3*2*1 => 2: 3개, 5: 0개

5!= 5*2*2*3*2*1 => 2: 3개, 5: 1개

6!= 2*3*5*2*2*3*2*1 => 2: 4개, 5: 1개

7!= 7*2*3*5*2*2*3*2*1 => 2: 4개, 5: 1개

8!= 2*2*2*7*2*3*5*2*2*3*2*1 => 2: 7개, 5: 1개

9!= 9*2*2*2*7*2*3*5*2*2*3*2*1 => 2: 7개, 5: 1개

10!= 2*5*9*2*2*2*7*2*3*5*2*2*3*2*1 => 2: 8개, 5: 2개


1!~ 10! 까지 계산된 수를 모두 구해서 정답을 구해보면 위의 규칙성 중 팩토리얼 숫자 중 2로 구성된 수의 갯수와 5로 구성된 수의 갯수 중 더 적은 갯수와 일치함을 알 수 있습니다.

알고리즘을 알았으니 반복문을 통해 식을 작성할 텐데 각 팩토리얼 수의 2와 5의 갯수를 구하는 식은 아래 소스코드에 나와있습니다.


코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
    cin.tie(0);
    cin.sync_with_stdio(false);
    int n;
    int two = 0, five = 0;
    cin >> n;
    
    for (int i = 2; i <= n; i = i * 2)
    
        two += n / i;
    for (int i = 5; i <= n; i = i * 5)
        five += n / i;
 
    cout << min(two, five);
    
    return 0;
}
cs


결과




'문제풀이(BOJ) > 규칙찾기' 카테고리의 다른 글

[백준 14954] Happy Number  (0) 2020.03.10
[백준 1652] 누울 자리를 찾아라  (2) 2020.01.15
[백준 1855] 암호  (0) 2020.01.06
[백준 3076] 상근이의 체스판  (0) 2020.01.03
[백준 1551] 수열의 변화  (0) 2020.01.03

문제출처: https://www.acmicpc.net/problem/14954


풀이

영어로된 문제라 당연스럽게 구글번역으로 한글로 바꿔서 풀었습니다ㅋㅋ;

문제를 요약하면, N의 자릿값을 계속 더해나갈 때 그 값이 언젠간 1이 되면 Happy number가 되고, 아닐 시 Unhappy number가 됩니다.

아닐 경우 문제에서 예로 들어준 5를 보면

5-> 25-> 29-> 85-> 89-> 145-> 42-> 20->4->16->37->58->89->----- 순으로 이어지는데 결국 기존에 나왔던 89가 또한번 나타나므로 

결국,  수식을 계속 계산해나갈 때 기존의 값이 또 나오면 Unhappy number임을 알 수 있습니다.

핵심은 한번 계산할 때 마다 담아놨던 값들에 대해서 일일히 또 나타나는 값인지 확인해야한다는 것입니다.

그 과정에서 주석 친 29~31행위치에 코드를 작성하지 않도록 주의하면 될 것 같습니다.


코드

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
42
43
44
45
46
47
48
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
vector<int>v;
int main()
{
    int n, temp = 0;
    cin >> n;
    if (n == 1)
    {
        cout << "HAPPY" << endl;
        return 0;
    }
    temp = n;
    int num = 0;
    while (1)
    {
        while (temp)
        {
            num += (temp % 10* (temp % 10);
            temp /= 10;
        }
        if (num == 1)
        {
            cout << "HAPPY" << endl;
            return 0;
        }
        /*v.push_back(num);
        temp = num;
        */
        //누적되어있는 값들중에서 기존에있었던 값인지확인
        for (int i = 0; i < v.size(); i++)
        {
            if (v[i] == num)
            {
                cout << "UNHAPPY" << endl;
                return 0;
            }
        }
        //재시작
        v.push_back(num);
        temp = num;
        num = 0;
    }
    
    
}
cs


결과



'문제풀이(BOJ) > 규칙찾기' 카테고리의 다른 글

[백준 1676] 팩토리얼 0의 개수  (0) 2020.08.27
[백준 1652] 누울 자리를 찾아라  (2) 2020.01.15
[백준 1855] 암호  (0) 2020.01.06
[백준 3076] 상근이의 체스판  (0) 2020.01.03
[백준 1551] 수열의 변화  (0) 2020.01.03

문제출처: https://www.acmicpc.net/problem/1652

 

분류는 수학으로되어있는데 규칙찾기문제같네요...

 

풀이

문제를 잘 이해하셔야합니다. 단순히 연속된 좌표가 '.'일때만 체크해주면 좋겟지만, 예외상황이 존재합니다.

대표적으로 ..XX..일때입니다.(세로표현도 똑같음.) 이 경우, 가로로보면 누울자리가 1개가 아니라 2개입니다. 이 예외만 처리해주면되고, 저 같은 경우 현재 좌표가 '.'일때, 'X'일때로 나눠서 row와 col값을 계산했습니다.

 

코드

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include<iostream>
using namespace std;
char map[100][100];
int n, cnt, row, col;
int main()
{
    cin >> n;
    for (int i = 0; i < n; i++)
        cin >> map[i];
 
    //가로부터.
    //'.'이면 cnt++
    //'x'만났는데 cnt>=2면 답+1,cnt=0;
    //'x'만나면 cnt=0;
    for (int i = 0; i < n; i++)
    {
        cnt = 0;
        for (int j = 0; j < n; j++)
        {
            //짐이없으면 일단 한칸증가
            //cnt>=2면 ans++
            if (map[i][j] == '.')
                cnt++;
            else if (map[i][j] == 'X')
            {
                if (cnt >= 2)
                {
                    row++;
                    cnt = 0;
                }
                else
                    cnt = 0;
            }
        }
        if (cnt >= 2)
            row++;
    }
    //세로도 똑같이
    for (int i = 0; i < n; i++)
    {
        cnt = 0;
        for (int j = 0; j < n; j++)
        {
            //짐이없으면 일단 한칸증가
            //cnt>=2면 ans++
            if (map[j][i] == '.')
                cnt++;
            else if (map[j][i] == 'X')
            {
                if (cnt >= 2)
                {
                    col++;
                    cnt = 0;
                }
                else
                    cnt = 0;
            }
        }
        if (cnt >= 2)
            col++;
    }
    cout << row << " " << col << endl;
}
cs

결과

'문제풀이(BOJ) > 규칙찾기' 카테고리의 다른 글

[백준 1676] 팩토리얼 0의 개수  (0) 2020.08.27
[백준 14954] Happy Number  (0) 2020.03.10
[백준 1855] 암호  (0) 2020.01.06
[백준 3076] 상근이의 체스판  (0) 2020.01.03
[백준 1551] 수열의 변화  (0) 2020.01.03

문제출처: https://www.acmicpc.net/problem/1855


문제

준표와 세준이는 서로 솔루션을 토론 하면서 다른 사람이 자신들의 솔루션을 듣지 못하게 하도록 서로 메시지를 주고받을 때 메시지를 암호화 하여서 주고받았다. 암호를 만드는 방법은 다음과 같다. 먼저 암호화 할 문자열을 1,1부터 위에서 아래 순서대로 채운다. 그리고 가장 밑의 행을 채운 후에는 오른쪽 열에서 다시 같은 과정을 반복한다.

만약에 "abcdefghijkl" 이라는 문자열을 3개의 열로 암호화 한다고 하자. 그러면 다음과 같이 표를 채울 수 있을 것이다.

a

e

i

b

f

j

c

g

k

d

h

l

그런 후에는 이제 왼쪽-> 오른쪽, 오른쪽-> 왼쪽, 왼쪽->오른쪽 ... 으로 읽으면서 다시 문자열을 만든다. 위의 경우에는 "aeijfbcgklhd" 가 될 것이다.

우리가 할 일은 다음과 같다. 암호화 된 문자열과 몇 개의 열로 암호화를 하였는지 주어져 있을 때 원래의 문자열을 구하는 프로그램을 작성하여라.


입력

열의 개수 K(1≤K≤20)가 주어지고 두 번째 줄에는 암호화 된 문자열(모두 영소문자)이 주어진다. (문자열의 길이는 200 이하이며 K의 배수이다.)


출력

첫 줄에 원래의 문자열을 출력한다..


풀이

이런 특정한 순서대로 입력된 수를 다시 출력 하는문제들은 노트에 대고 규칙을 찾아보면 금방 풀 수 있습니다. 

문제에서 문자열의 최대길이는 200이고 열의 최대길이는 20이므로 행은 최대 10임을 알 수 있습니다. 곧, 문제의 표를 만들기 위한 2차원 배열의 사이즈는 

map[10][20] 이 최대입니다. 저는 문제의 표를 만들고 규칙대로 풀었는데, 표를보면 짝수행은 정방향, 홀수행은 역방향으로 문자들이 이어집니다.

짝수행일 때 어떻게 표를 만들까요? 

2행을 예로들면, map[2][0]=s[0], map[2][1]=s[7], map[2][2]=s[8]인데, 규칙을 보면 각 값들이 (행*k) + 0, (행,*k)+1, (행*k)+2의 규칙성을 볼 수 있습니다.

홀수행일 때 3행을 보면 map[3][0]=s[11], map[3][1]=s[10], map[3][2]=s[9]인데 각 값들이 (행*k)+2, (행*k)+1, (행*k)+0의 규칙성을 갖습니다.

이를 소스코드로 구현 후 조건대로 출력하면됩니다.


코드

#include<iostream>
#include<string>
using namespace std;
char map[10][20];
int main()
{
	int k;
	string s;
	cin >> k;
	cin >> s;
	for (int i = 0; i < s.size() / k; i++)
	{
		if(i%2==0)//짝수행
			for (int j = 0; j < k; j++)
			{
				map[i][j] = s[i * k + j];
			}
		else
		{
			int c = k - 1;
			for (int j = 0; j < k; j++)
			{
			
				map[i][j] = s[i*k+c];
				c--;
			}
		}
	}
	for (int i = 0; i < k; i++) {
		for (int j = 0; j < s.size() / k; j++) {
			cout << map[j][i];
		}
	}
	cout << endl;
}


결과

'문제풀이(BOJ) > 규칙찾기' 카테고리의 다른 글

[백준 14954] Happy Number  (0) 2020.03.10
[백준 1652] 누울 자리를 찾아라  (2) 2020.01.15
[백준 3076] 상근이의 체스판  (0) 2020.01.03
[백준 1551] 수열의 변화  (0) 2020.01.03
[백준 10996] 별 찍기- 21  (0) 2020.01.02

문제출처: https://www.acmicpc.net/problem/3076


문제

상근이는 체스판을 만들려고 한다.

체스판은 검정칸과 흰칸으로 이루어져 있다. 가장 왼쪽 위칸의 색은 검정색이고, 나머지 색은 검정과 흰색이 번갈아가면서 등장한다. 검정색은 'X'로, 흰색은 '.'로 표시한다.

상근이의 체스판은 R행 * C열로 이루어져 있어야 한다. 또, 각각의 행의 높이는 문자 A개만큼 이며, 각각의 열의 너비는 문자 B개 만큼이다. 예제 출력을 보고 이해하면 쉽다.

R, C, A, B가 주어졌을 때, 상근이의 체스판을 출력하는 프로그램을 작성하시오.


입력

첫째 줄에 두 양의 정수 R과 C가 주어진다. (1 ≤ R, C ≤ 10)

둘째 줄에 두 양의 정수 A와 B가 주어진다. (1 ≤ A, B ≤ 10)


출력

출력은 R * A행 C * B열로 이루어져 있어야 하며, 문제에서 설명한 상근이의 체스판을 출력한다.


풀이

별찍기 문제 응용문제라고 생각하면됩니다. 다만, 반복문을 어디까지 이해하고 쓸줄 아느냐가 중요합니다.

처음엔 반복문을 구성할 때 행에 대해 for(int i=0; i<r*a;i++), 열에 대해 for(int j=0; j<c*b;j++)이렇게 반복문을 작성하였는데 이렇게 작성하면 문제에서 주어진 규칙성을 응용하지않고 하나하나 규칙을  따로 찾아서 구현해야하므로 까다롭기 때문에 반복되는 규칙을 곧바로 코드로 옮기면 풀이가 쉬워집니다. 소스코드는 말보다 직접보는게 이해가 빠를 것 같아서 주석으로 달아놓았고, 중요한 건 19행의 조건문입니다

행과 열에서 각각 덩어리로 구성되는 문자열 "xxx", "..."을 각각 하나로 보되 각각 a,b만큼 찍히는만큼 하나로 보는겁니다.

보기에서 1행과2행을 한덩어리로 보고, 열에서 "xxx", "..."을 각각 한 덩어리로 보면 i,j로 갖고노는 단순 반복문구성이됩니다.


코드

#include<iostream>
using namespace std;
int main()
{
	int r, c, a, b;
	cin >> r >> c >> a >> b;
	//5행을
	for (int i = 0; i < r; i++)
	{
		//2번씩 출력=총 10줄
		for (int j = 0; j < a; j++)
		{
			//1열당 5개의덩어리
			for (int k = 0; k < c; k++)
			{
				//그 5개가 각각 3개의문자이룸
				for (int l = 0; l < b; l++)
				{
					if ((i + k) % 2 == 0)
						cout << "X";
					else cout << ".";
				}
			}
			cout << endl;
		}
	}
}


결과



'문제풀이(BOJ) > 규칙찾기' 카테고리의 다른 글

[백준 1652] 누울 자리를 찾아라  (2) 2020.01.15
[백준 1855] 암호  (0) 2020.01.06
[백준 1551] 수열의 변화  (0) 2020.01.03
[백준 10996] 별 찍기- 21  (0) 2020.01.02
[백준 11312] 삼각 무늬-2  (0) 2019.12.15

문제출처: https://www.acmicpc.net/problem/1551


문제

크기가 N인 수열 A가 주어졌을 때, 세준이는 인접한 두 원소의 차이를 이용해서 크기가 N-1인 수열 B를 만들 수 있다.

예를 들어, A = {5,6,3,9,-1} 이었을 때, B = {6-5, 3-6, 9-3, -1-9} = {1,-3,6,-10}이 된다. 다른 말로 B[i] = A[i+1]-A[i]가 된다.

수열 A가 주어졌을 때, 세준이가 위의 방법을 K번 했을 때 나오는 수열을 구하는 프로그램을 작성하시오.


입력

첫째 줄에 수열의 크기 N과 K가 주어진다. N은 20보다 작거나 같은 자연수이고, K는 0보다 크거나 같고, N-1보다 작거나 같은 자연수이다. 둘째 줄에는 수열이 ‘,’로 구분되어 주어진다.


출력

첫째 줄에 K번 변형한 수열을 ‘,’로 구분하여 출력한다.


풀이

한 턴이 지날때 마다 저장된 값의 개수가 한개씩 줄어들어서 이 요소들을 어떻게 담을까 고민한문제입니다. 결국은 규칙만 찾아서 이중 반복문으로

해결 할 수 있었고 간단한 문제였습니다.

조건에 맞게 배열index로 입력받고 k번 수행 할 때 남은 요소들을 출력할 차례인데, 이 때 규칙을 보면 n개의 요소는 k(1부터시작)가 증가 할 때 마다 한개 씩 줄어듭니다. 

ex)k가 3일 때 

5,6,3,9,-1 -> 1,-3,6,-10 (4개) -> -4,3,-16 (3개) -> 7,-19 (2개)

즉, i~k번 연산하는 동안 n개의 요소들이 각각 변화하는 과정을 연산하되, 한번의 연산 후 요소의 개수가 한개 씩 줄어들어야합니다. 

결론적으로 18행이 그 연산코드입니다. 연산 후 조건에 맞게 출력하면됩니다.


코드

#pragma warning(disable:4996)
#include<iostream>
using namespace std;
int arr[21];
int main()
{
	int n, k;
	cin >> n >> k;
	for (int i = 0; i < n; i++)
	{
		if (i < n - 1)
			scanf("%d,", &arr[i]);
		else
			scanf("%d", &arr[i]);
	}
	for (int i = 0; i < k; i++)
	{
		for (int j = 0; j <n-1-i;j++)
		{
			arr[j] = arr[j + 1] -arr[j];
		}
	}
	cout << arr[0];
	for (int i = 1; i < n - k; i++)
		cout << ',' << arr[i];
	cout << endl;
}


결과






'문제풀이(BOJ) > 규칙찾기' 카테고리의 다른 글

[백준 1855] 암호  (0) 2020.01.06
[백준 3076] 상근이의 체스판  (0) 2020.01.03
[백준 10996] 별 찍기- 21  (0) 2020.01.02
[백준 11312] 삼각 무늬-2  (0) 2019.12.15
[백준 1834] 나머지와 몫이 같은 수  (0) 2019.12.13

문제출처: https://www.acmicpc.net/problem/10996


문제

예제를 보고 규칙을 유추한 뒤에 별을 찍어 보세요.


입력

첫째 줄에 N(1 ≤ N ≤ 100)이 주어진다.


출력

첫째 줄부터 차례대로 별을 출력한다.


풀이

별찍기를 풀 때 마다 느끼지만 재귀를 사용한 고난이도의 별찍기문제가 아닌이상 90%가 i,j를 이용한 연산만으로도 풀리는것같습니다.

즉, 별찍기를 어려워하는것은 아직 규칙성을 발견하여 코딩하는 연습이 부족하다는 것입니다.( 풀 때 마다 실력이 늡니다.) 문제를 살펴보면, 행의 갯수는 n*2, 한개의 열에 등장하는 공백+별의 갯수는 1~n개 라는 것을 알아야합니다. 그리고, 별이 찍히는 위치가 행마다 달라지는데, 행이 홀수냐 짝수냐에 따라, 그리고 그 때의 현재 열이 홀수냐 짝수냐에 따라 별과 공백의 위치가 엇갈리는 것을 확인할 수 있습니다. 코드로 옮기면 끝입니다.


코드

#include<iostream>
using namespace std;
int main()
{
	int n;
	cin >> n;
	for (int i = 1; i <= n * 2; i++)
	{
		for (int j = 1; j <= n; j++)
		{
			if (i % 2 == 0)
			{
				if (j % 2 == 0)
					cout << "*";
				else cout << " ";
			}
			else
			{
				if (j % 2 == 0)
					cout << " ";
				else cout << "*";
			}
		}
		cout << endl;
	}
}


결과



문제출처: https://www.acmicpc.net/problem/11312


문제

무엇이든 덮어버리는 것을 좋아하는 지은이는 한변의 길이가 A인 정삼각형을 한변의 길이가 B인 정삼각형으로 완전히 덮어 버리고자 한다. 

두개의 정수 A, B 가 주어지고, B ≤ A 이고, A를 B로 나눌수 있을때, 한 변의 길이가 A인 정삼각형을 완전하게 덮기 위한, 한변의 길이가 B인 정삼각형의 개수를 구하라.

입력

첫째 줄에 테스트 케이스의 개수 T가 주어진다. (T ≤ 1000)

각각의 테스트 케이스는 한줄로 이루어져 있으며 두개의 정수 A, B 가 (1 ≤ B ≤ A ≤ 1,000,000, B|A) 주어진다.


출력

각 테스트 케이스마다 한변의 길이가 A인 정삼각형을 완벽하게 덮을 수 있는 한변의 길이가 B인 정삼각형의 최소 개수를 출력한다.


풀이

규칙찾기문제입니다. 노트에 알고리즘을 설계하고 그것을 소스코드로 구현하는 능력을 기르기 위해 일부러 노트에 카테고리명을 노트에풀기라고 지었습니다.

규칙을 찾아볼까요? (그려보면 암) 2 1 일 때 답=4, 3 1 일때 답=9,  4 1 일때 답=16 입니다. 따라서 b가1일때 정답은 a^2이죠. 그리고 문제조건에의해 a%b=0이어야하므로  4 2일때를보면 4, 그리고 6 2 일 때를보면 9, 6 3일때는 4입니다. 결국 정답은 (a/b)^2가됩니다. 주의할것은 int형범위를 넘길 수 있으므로 longlong형으로 정답을 출력해야합니다.


코드

#pragma warning(disable:4996)
#include<iostream>
using namespace std;
int main()
{
	int t;
	long long a, b;
	scanf("%d", &t);
	for (int i = 0; i < t; i++)
	{
		scanf("%lld%lld", &a, &b);
		printf("%lld\n", a / b * a / b);
	}
}


결과

+ Recent posts