1052번: 물병 (acmicpc.net)

 

1052번: 물병

지민이는 N개의 물병을 가지고 있다. 각 물병에는 물을 무한대로 부을 수 있다. 처음에 모든 물병에는 물이 1리터씩 들어있다. 지민이는 이 물병을 또 다른 장소로 옮기려고 한다. 지민이는 한 번

www.acmicpc.net

1리터의 물이 들어있는 n개의 물병을 이용해 k개를 넘지 않는 비어있지 않은 물병을 만드는 문제이다. k개 이하의 물병을 만들기 위해서 상점에서 추가적으로 1리터의 물이 들어있는 n개의 물병을 사올 수 있는데, 이때 최소한으로 사오는 갯수를 구하여야 한다.

물은 아래와 같이 재분배한다.

먼저 같은 양의 물이 들어있는 물병 두 개를 고른다. 그 다음에 한 개의 물병에 다른 한 쪽에 있는 물을 모두 붓는다. 이 방법을 필요한 만큼 계속 한다.

.

#include <iostream>

using namespace std;

int test(int a) {
	int b = 0;
	while (1) {
		if (a == 1) {
			b++;
			break;
		}
		if (a % 2 == 1) {
			a--;
			b++;
		}
		else {
			a = a / 2;
		}
	}
	return b;
}

int main() {
	int n, k,a=0,b=1;
	cin >> n >> k;
	if (k >= n) {
		cout << 0;
	}
	else {
		while (1) {
			if (test(n)<=k) {
				break;
			}
			if (n % 2 == 0) {
				n = n / 2;
				b = b * 2;
			}
			else {
				n = n + 1;
				a = a + b;
			}
			
		}
		cout << a;
	}
}

 

나의 접근 방식은, 우선 같은 양의 물을 합칠 수 있을 만큼 합친 후, 홀수개가 되어 물병이 남게 될 경우 상점에서 추가로 물병을 사와 짝수개로 만들어주어 다시 합치는 방식으로 구현하였다. 예를 들어 100개의 물병이 있을 때 25개까지 합칠 수 있는데, 이 25개의 물병 각각의 물 양은 4리터가 될 것이다. 따라서 물병을 26개로 만들기 위해 상점에서 1리터 *4개의 물병을 사왔다.  이 과정에서 2,4,8,16,... 등 2의 제곱수만큼의 물병이 사올 때 마다 더해지게 된다.

루프 중 합쳐진 물병의 개수가 주어진 k개 이하로 나누어질 수 있는 경우 (이는 test함수를 구현하여 확인함. test의 경우 n을 2로 나눌 수 있을 만큼 나누고, 홀수가 된 경우 물병 하나를 빼는것과 동일하게 n에 -1을 해주었다. 최종적으로 n을 1까지 나누면 빼둔 물병에 n+1을 해주면 n개 물병을 합친 최솟값을 구할 수 있다.) 루프를 탈출하고 최종적으로 값을 출력하면 된다.

'백준' 카테고리의 다른 글

백준 1074번 - Z  (0) 2023.07.25
백준 1291번 - 이면수와 임현수  (0) 2023.07.24
백준 1002번 - 터렛  (0) 2023.07.23
백준 1051번 - 숫자 정사각형  (0) 2023.07.21
백준 2108번 - 통계학  (0) 2023.07.21

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

 

1074번: Z

한수는 크기가 2N × 2N인 2차원 배열을 Z모양으로 탐색하려고 한다. 예를 들어, 2×2배열을 왼쪽 위칸, 오른쪽 위칸, 왼쪽 아래칸, 오른쪽 아래칸 순서대로 방문하면 Z모양이다. N > 1인 경우, 배열을

www.acmicpc.net

크기가 2N × 2N인 2차원 배열을 Z모양으로 탐색하려고 하는데, 예를 들어 2×2배열을 왼쪽 위칸, 오른쪽 위칸, 왼쪽 아래칸, 오른쪽 아래칸 순서대로 방문하면 Z모양으로 탐색하는 것이라고 한다.

이게 n이 3일때의 방문 순서도이다.

#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>

using namespace std;



int main() {
	int n;
	int r, c;
	vector< long long > range;
	cin >> n >> r >> c;
	int a = pow(2, n);
	int b = 0;
	int d = pow(2, n);
	int e = 0;
	range.push_back(0);
	range.push_back(pow(2, 2*n)-1);
	while (n>0) {
		long long x = range[1] - range[0] + 1;
		if (r >= (a+b)/2 && c >= (d+e)/2) {
			range[0] = range[0] + 3 * x / 4;
			b = (a + b) / 2;
			e = (d+e) / 2;
		}
		else if (r >= (a + b) / 2 && c < (d + e) / 2) {
			range[0] = range[0] + 2 * x / 4;
			range[1] = range[0] + x / 4 - 1;
			b = (a+b) / 2;
			d = (d+e) / 2;
		}
		else if (r < (a + b) / 2 && c >= (d + e) / 2) {
			range[0] = range[0] + x / 4;
			range[1] = range[0] + x / 4 - 1;
			a = (a + b) / 2;
			e = (d + e) / 2;
		}
		else {
			range[1] = range[0] + x / 4 - 1;
			a = (a + b) / 2;
			d = (d + e) / 2;
		}
		n--;
	}
	cout << range[0];
}

우선 본인은 숫자의 범위를 정해 놓고, n을 줄여가며 사분면에 따라서 수의 위치를 분류하는 방법을 사용했다. r,c의 범위에 따라서 사분면을 정하고, 그 사분면의 숫자들을 범위를 통해 다시 저장해 주는 방법을 사용했다.

'백준' 카테고리의 다른 글

백준 1052번 - 물병  (0) 2024.01.19
백준 1291번 - 이면수와 임현수  (0) 2023.07.24
백준 1002번 - 터렛  (0) 2023.07.23
백준 1051번 - 숫자 정사각형  (0) 2023.07.21
백준 2108번 - 통계학  (0) 2023.07.21

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

 

1291번: 이면수와 임현수

11은 메갈루젼 문명의 어비스 오엘 우테에 속하지만 각 자리수의 총합이 1+1=2, 즉 짝수이므로 이면수가 아니고 chicken number혹은 starcraft number도 아니고 합성수도 아니므로 임현수가 아니다. 고로

www.acmicpc.net

설명이 되게 긴데 읽어보면 말장난 위주여서 재미있었다. 

우선 요약하자면

1. 어떤 숫자가 “이면수”이기 위해서는 [어비스 오엘 우테(absolute)]에 속해 있어야 하고, 각 자릿수의 합이 홀수여야 한다.

여기서 어비스 오엘 우테는 2와 3의 합으로 표현되는 숫자들, 즉 6, 7, 8, 9, 10 ... 을 말한다. 

2. 어떤 숫자가 "임현수“이기 위해서는 그 숫자가 자체가 월드 문명의 chicken number 혹은 starcraft number이거나 합성수이면서 소인수 분해를 했을 때 소인수의 종류의 개수가 짝수개 이어야 한다.

여기서  chicken number와 starcraft number 은 각각 4, 2를 의미한다.

3. 이면수이면 1, 임현수이면 2, 임현수와 이면수 둘다 아니면 3, 둘다 이면 4를 출력한다.

#include <iostream>
#include <cmath>
#include <vector>

using namespace std;

int digit(int n) {
	int a = 0;
	while (1) {
		int b = n / pow(10, a);
		if (b < 10)
		{
			break;
		}
		a++;
	}
	return a + 1;
}

bool check소수(int n) {
	int a = 2;
	if (n == 1) {
		return false;
	}
	else {
		while (1) {
			int b = n % a;
			if (b == 0) {
				break;
			}
			a++;
		}
		if (n == a) {
			return true;
		}
		else {
			return false;
		}
	}
}

bool check이면수(int n) {
	int temp = n;
	int a = digit(n);
	vector<int> v;
	while (a>1) {
		int i = n / pow(10, a - 1);
		v.push_back(i);
		n = n - (i * pow(10, a - 1));
		a--;
	}
	v.push_back(n);
	int b = 0;
	for (int i = 0; i < v.size(); i++) {
		b += v[i];
	}
	if (temp >= 4 && temp!=5 && b % 2 == 1) {
		return true;
	}
	else {
		return false;
	}
}

bool check임현수(int n) {
	vector<int> v;
	if (n == 2 || n == 4) {
		return true;
	}

	else if (check소수(n) == true || n==1) {
		return false;
	}
	else {
		for (int i = 2; i < n; i++) {
			int a = n % i;
			if (a == 0 && check소수(i)==true) {
				v.push_back(i);
			}
		}
		if (v.size() % 2 == 0) {
			return true;
		}
		else {
			return false;
		}
	}
}

int main() {
	int n;
	cin >> n;
	if (check임현수(n) == true && check이면수(n) == true) {
		cout << 4;
	}
	else {
		if (check이면수(n) == true) {
			cout << 1;
		}
		else if(check임현수(n)==true) {
			cout << 2;
		}
		else {
			cout << 3;
		}
	}
}

조금 복잡하긴 하지만, 자리수 체크와 소수 판정, 이면수와 임현수를 판정하는 함수들을 각각 만들어 주었다. 1의 경우 예외처리가 필요했다.

'백준' 카테고리의 다른 글

백준 1052번 - 물병  (0) 2024.01.19
백준 1074번 - Z  (0) 2023.07.25
백준 1002번 - 터렛  (0) 2023.07.23
백준 1051번 - 숫자 정사각형  (0) 2023.07.21
백준 2108번 - 통계학  (0) 2023.07.21

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

 

1002번: 터렛

각 테스트 케이스마다 류재명이 있을 수 있는 위치의 수를 출력한다. 만약 류재명이 있을 수 있는 위치의 개수가 무한대일 경우에는 $-1$ 출력한다.

www.acmicpc.net

두 점의 좌표가 주어지고, 각각의 점으로부터 r1, r2만큼의 거리에 있는 상대의 위치를 찾는 문제이다. 있을 수 있는 곳을 찾는 것이기 때문에 여러가지 경우가 생긴다.  따라서 원으로 그리면 편하다. 결국 두 원의 접점이 몇개인지를 찾는 문제이다.

#include <iostream>
#include <cmath>

using namespace std;

int main() {
	int n, x1, y1, r1, x2, y2, r2;
	cin >> n;
	for (int i = 0; i < n; i++) {
		cin >> x1 >> y1 >> r1 >> x2 >> y2 >> r2;
		double d = sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2));
		if (x1 == x2 && y1 == y2) {
			if (r1 == r2) {
				cout << -1<<endl;
			}
			else {
				cout << 0<<endl;
			}
		}
		else {
			if (d > r1 + r2 || d < sqrt(pow(r2 - r1, 2))) {
				cout << 0<<endl;
			}
			else if (d + r1 == r2 || d + r2 == r1 || d == r1 + r2) {
				cout << 1<<endl;
			}

			else {
				cout << 2<<endl;
			}
		}
		
	}
}

두 원의 중심점이 일치하는 경우에는 반지름(r)이 같은지에 따라서 점점이 무한대일수도, 0개일수도 있기에 먼저 예외처리를 해주었다.

두 원의 반지름의 합이 두 원의 중심점 거리보다 짧을 경우나 중심점 거리와 한 원의 반지름의 합이 다른 원의 반지름보다 짧은 경우 0개의 접점, 반지름의 합이 거리와 같을 경우와 원 안에서 접할 경우 1개의 접점, 그 외의 경우 2개의 접점을 출력하도록 구현해주었다.

'백준' 카테고리의 다른 글

백준 1052번 - 물병  (0) 2024.01.19
백준 1074번 - Z  (0) 2023.07.25
백준 1291번 - 이면수와 임현수  (0) 2023.07.24
백준 1051번 - 숫자 정사각형  (0) 2023.07.21
백준 2108번 - 통계학  (0) 2023.07.21

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

 

1051번: 숫자 정사각형

N×M크기의 직사각형이 있다. 각 칸에는 한 자리 숫자가 적혀 있다. 이 직사각형에서 꼭짓점에 쓰여 있는 수가 모두 같은 가장 큰 정사각형을 찾는 프로그램을 작성하시오. 이때, 정사각형은 행

www.acmicpc.net

3 5
42101
22100
22101

이런 식으로 수가 주어졌을 때 모서리 숫자가 같은 정사각형들 중 가장 큰 크기의 정사각형의 크기를 찾는 문제이다.

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main() {
	int n, m;
	string x;
	cin >> n >> m;
	vector<string> v;
	vector<int> v1;
	for (int i = 0; i < n; i++) {
		cin >> x;
		v.push_back(x);
	}
	for (int k = 0; k < n; k++) {
		for (int i = 0; i < m; i++) {
			for (int j = i; j < m; j++) {
				if (v[k][i] == v[k][j]) {
					int a = j - i + 1;
					for (int l = k; l < n; l++) {
						if (v[k][i] == v[l][i]) {
							if (v[k][j] == v[l][j]) {
								int b = l - k + 1;
								if (a == b) {
									v1.push_back(a * b);
								}
							}
						}
					}
				}
			}
		}
	}
	int max = *max_element(v1.begin(), v1.end());
	cout << max;
}

for문을 사용해 가로줄에서 같은 숫자 두개를 찾았고, 그 숫자들 기준으로 세로줄에 같은 숫자가 있으면 직사각형을 찾은 것이다. 문제에서는 정사각형을 찾으라고 하였기에 a,b가 같은 경우만 크기로 저장해 주었다.

저장된 크기 중 가장 큰 값을 찾으면 된다.

'백준' 카테고리의 다른 글

백준 1052번 - 물병  (0) 2024.01.19
백준 1074번 - Z  (0) 2023.07.25
백준 1291번 - 이면수와 임현수  (0) 2023.07.24
백준 1002번 - 터렛  (0) 2023.07.23
백준 2108번 - 통계학  (0) 2023.07.21

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

 

2108번: 통계학

첫째 줄에 수의 개수 N(1 ≤ N ≤ 500,000)이 주어진다. 단, N은 홀수이다. 그 다음 N개의 줄에는 정수들이 주어진다. 입력되는 정수의 절댓값은 4,000을 넘지 않는다.

www.acmicpc.net

  1. 산술평균 : N개의 수들의 합을 N으로 나눈 값
  2. 중앙값 : N개의 수들을 증가하는 순서로 나열했을 경우 그 중앙에 위치하는 값
  3. 최빈값 : N개의 수들 중 가장 많이 나타나는 값
  4. 범위 : N개의 수들 중 최댓값과 최솟값의 차이

주어진 n개의 수들에 대하여 위의 4가지 값을 구하는 문제이다.

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
64
65
66
#include <iostream>
#include<vector>
#include <algorithm>
using namespace std;
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    int n;
    int x;
    cin >> n;
    int* a = new int[n];
    vector<int> v;
    for (int i = 0; i < n; i++) {
        cin >> x;
        a[i] = x;
    }
    double b = 0;
    for (int i = 0; i < n; i++) {
        b += a[i];
    }
    if (b < 0) {
        int c = int(-1 * (b / n) + 0.5* -1;
        cout << c << '\n';  //음수 산술평균을 반올림
    }
    else {
        int c = int((b / n) + 0.5);
        cout << c << '\n';  //양수 산술평균을 반올림
    }
    for (int i = 0; i < n - 1; i++) {
        for (int j = i + 1; j < n; j++) {
            if (a[i] > a[j]) {
                int temp = a[i];
                a[i] = a[j];
                a[j] = temp;
            }
        }
    }
    cout << a[(n - 1/ 2<< '\n'//위에서 오름차순으로 정렬한 값들중 중간값
    for (int i = 0; i < n - 1; i++) {
        int d = 1;
        for (int j = i + 1; j < n; j++) {
            if (a[i] == a[j]) {
                d++;
            }
        }
        v.push_back(d);
    }  // 이중 for문으로 최빈값을 구하려고 시도했음
    v.push_back(1);
    int e = 0;
    int max_index = max_element(v.begin(), v.end()) - v.begin();
    for (int i = max_index + 1; i < n; i++) {
        if (v[i] == v[max_index]) {
            e++;
        }
    }
    if (e == 0) {
        cout << a[max_index] << '\n'
    }
    else {
        v[max_index] = 0;
        int max_index1 = max_element(v.begin(), v.end()) - v.begin();
        cout << a[max_index1] << '\n';
    }
    cout << a[n - 1- a[0<< '\n'// 정렬한 표에서 가장 큰값과 ㅏㄱ은값 
}
cs

위의 코드처럼 하였더니 이중 for문에서 overflow가 발생하여 시간 초과가 나타났다. 

그래서 입력되는 정수 값들이 4000을 넘지 않는다는 점을 이용해 0부터 8000까지의 인덱스를 가지는 벡터1을 새로 만들어주고, 입력받은 숫자의 값 +4000 을 한 값이 몇번 등장하는지를 벡터 1의 각 인덱스의 값을 증가시킴으로써 기록해 주었다.

(예를 들자면 1을 입력 받을 경우 벡터 1의 4001번째 인덱스에 해당하는 값을 +1 해주어 횟수를 기록하는 방식이다.)

마지막에 최빈값에 해당하는 인덱스에서 4000을 뺀 값을 답으로 출력하면 된다. 최빈값이 여러개일 경우 벡터 1의 최빈값에 해당하는 인덱스를 0으로 만들어 주어 다시 최빈값을 찾는 방식으로 최빈값 중 두번째로 작은 수를 찾아낼 수 있었다.

아래는 수정한 코드이다.

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
#include <iostream>
#include<vector>
#include <algorithm>
using namespace std;
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    int n;
    int x;
    cin >> n;
    vector<int> a;
    vector<int> v;
    for (int i = 0; i < 8001; i++) {
        v.push_back(0);
    }
    for (int i = 0; i < n; i++) {
        cin >> x;
        a.push_back(x);
    }
    double b = 0;
    for (int i = 0; i < n; i++) {
        b += a[i];
    }
    if (b < 0) {
        int c = int(-1*(b / n) + 0.5)*-1;
        cout << c << '\n';
    }
    else {
        int c = int((b / n) + 0.5);
        cout << c << '\n';
    }
    sort(a.begin(), a.end());
    cout << a[(n-1/ 2]<<'\n';
    for (int i = 0; i < n; i++) {
        v[a[i]+4000]++;
    }
    int e = 0;
    int max_index = max_element(v.begin(), v.end()) - v.begin();
    for (int i = max_index+1; i < 8001; i++) {
        if (v[i] == v[max_index]) {
            e++;
        }
    }
    if (e == 0) {
        cout << max_index-4000 << '\n';
    }
    else {
        v[max_index] = 0;
        int max_index1 = max_element(v.begin(), v.end()) - v.begin();
        cout << max_index1-4000 << '\n';
    }
    cout << a[n - 1- a[0<< '\n';
}
cs

'백준' 카테고리의 다른 글

백준 1052번 - 물병  (0) 2024.01.19
백준 1074번 - Z  (0) 2023.07.25
백준 1291번 - 이면수와 임현수  (0) 2023.07.24
백준 1002번 - 터렛  (0) 2023.07.23
백준 1051번 - 숫자 정사각형  (0) 2023.07.21

+ Recent posts