본문 바로가기
Algorithm/BAEKJOON

[백준] Solved.ac 랜덤 마라톤 (No. 6903, 11896, 15410, 11501, 9335, 6207, 2467, 12796)

by code_pie 2024. 6. 28.

Solved.ac 랜덤 마라톤 풀기


링크

 
fig
마라톤 문제

 

문제 + 풀이

 

[문제 후기]

 

A. Trident (9분)

문제 링크

 

간단하게 문제의 조건에 따라 삼지창을 그리면 된다.

for문을 이용하면 쉽게 그릴수 있는 문제다.

 

더보기

 구현

#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <set>
#include <algorithm>
#include <queue>
using namespace std;

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	int t,s,h;
	cin >> t>>s>>h;
	int tmp = s;
	string str = "";
	string str2 = "";
	string tmpSt = "";
	for (int i = 0; i < tmp; i++) {
		tmpSt += ' ';
	}
	str = '*' + tmpSt + '*' + tmpSt + '*';
	for (int i = 0; i < t; i++) {
		cout << str << "\n";
	}
	for (int i = 0; i < s; i++) {
		str2 += '*';
	}
	cout << "*"<<str2<<"*"<<str2<<"*\n";
	for (int i = 0; i < h; i++) {
		cout << ' ' << tmpSt << "*\n";
	}
	
	return 0;
}

 

B. 다각형 (9분)

문제 링크

 

이 문제는 잘 생각하면 n각형에서 n이 짝수일 경우만 하나의 선분으로 n각형의 변을 자를 수 있다.

그러므로 a~b 사이에 짝수인 변들의 합을 계산하면 되는 문제다.

 

더보기

구현

#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <set>
#include <algorithm>
#include <queue>
using namespace std;

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	int a, b;
	cin >> a >> b;
	long long stA = ((a + 1) / 2) * 2;
	long long edB = (b / 2) * 2;
	if (stA <= 2) {
		stA = 4;
	}
	if (edB < stA) {
		cout << 0;
	}
	else {
		long long num = ((edB - stA) / 2)+1;
		cout << num * (stA + edB) / 2;
	}
	return 0;
}


C. Cakey McCakeFace (30분)

문제 링크

 

이번 마라톤에서 가장 오래 걸린 문제다. 귀찮아서 번역해서 문제를 읽었더니 문제의 내용이 도저히 이해가 안돼서 한참을 고민했었다. 중간에 다시 여러 번 문제를 읽은 후에야 이해가 됐다.

 

문제의 내용을 쉽게 요약하면 빵을 굽는시간 t가 걸리는데 제대로 측정이 되지 않을 수 있다.

그러므로 빵을 굽는 시간 t를 특정 시간으로 가정했을 경우 제대로 측정된 경우가 가장 많은 경우를 찾고 그 때의 시간 t를 찾으면 되는 문제다.

이 문제는 시간이 겹치지 않으므로 모든 입력에 대해 빠져나오는 시간과 차이를 구하고, 그 중에서 가장 시간 차이가 같은 값이 많은 시간을 찾으면 되는 문제다.

 

 

더보기

구현

#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <set>
#include <algorithm>
#include <queue>
#include <unordered_map>
#include <set>
#include <map>
using namespace std;

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	int N, M;
	cin >> N >> M;
	vector<int> vN(N);
	vector<int> vM(M);
	unordered_map<int, int> mm;
	for (int i = 0; i < N; i++) {
		cin >> vN[i];
	}
	for (int i = 0; i < M; i++) {
		cin >> vM[i];
	}
	set<int> numSet;
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M; j++) {
			if (vM[j] - vN[i] >= 0) {
				mm[vM[j] - vN[i]] += 1;
			}
		}
	}
	vector<pair<int, int>> V(mm.begin(), mm.end());
	sort(V.begin(), V.end(), [](pair<int,int>a, pair<int,int>b) {
		return a.second == b.second ? a.first<b.first : a.second>b.second;
		});
	if (V.size() > 0) {
		cout << V[0].first;
	}
	else {
		cout << 0;
	}
	return 0;
}


D. 주식 (10분)

문제 링크

 

 

이 문제는 주식의 판매이익을 최대로 올리면 되는 문제다.

잘 생각하면 현재 주식가격보다 높은 주식이 없다면 주식을 안 사면 된다는 결론이 나온다.

그러므로 거꾸로 뒤에서부터 탐색을 시작해 주식의 최대가격을 저장해 나간다.

이후 이전에 등장했던 최대가격보다 더 높은 최대가격이 앞에 있다면, 앞에 등장하는 주식들은 갱신된 주식의 최대 가격으로 판매하면 된다.

 

더보기

구현

#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <set>
#include <algorithm>
#include <queue>
#include <unordered_map>
#include <set>
#include <map>
using namespace std;

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	int tc;
	cin >> tc;
	for (int t = 0; t < tc; t++) {
		int N;
		cin >> N;
		vector<int> v(N);
		for (int i = 0; i < N; i++) {
			cin >> v[i];
		}
		long long maxCost = v[N - 1];
		int cnt = 0;
		long long hap = 0;
		long long maxAns = 0;
		long long tmp;
		for (int i = N - 2; i >= 0; i--)
		{
			if (v[i] < maxCost) {
				cnt += 1;
				hap += v[i];
			}
			else
			{
				tmp = cnt * maxCost - hap;
				if (tmp > 0) {
					maxAns += tmp;
				}
				cnt = 0;
				hap = 0;
				maxCost = v[i];
			}
		}
		tmp = cnt * maxCost - hap;
		if (tmp > 0) {
			maxAns += tmp;
		}
		cout << maxAns << "\n";
	}
	return 0;
}

 

E. 소셜 광고 (18분)

문제 링크

 

이 문제는 나와 직접 연결된 친구만 광고가 같이 보여지기 때문에 완전 탐색을 해야한다.

최근에 비트마스킹을 익혔기 때문에 DFS 대신 비트마스킹으로 광고를 볼 친구들을 선택해 문제를 해결했다.

비트마스킹에서 광고를 받을 사람이 정해지면 그 사람과 친구들에게 광고를 보여준 후 모든 사람이 광고를 볼 수 있는지 체크하면 해결할 수 있는 문제였다.

 

 

더보기

구현

#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <set>
#include <algorithm>
#include <queue>
#include <unordered_map>
#include <set>
#include <map>
using namespace std;

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	int tc;
	cin >> tc;
	for (int t = 0; t < tc; t++) {
		int N;
		cin >> N;
		vector<int> V(N,0);
		int M, num;
		for (int i = 0; i < N; i++) {
			cin >> M;
			V[i] = 1 << i;
			for (int j = 0; j < M; j++) {
				cin >> num;
				V[i]|=1<<(num - 1);
			}
		}
		int idx, visited;
		int minV = N;
		for (int i = 1; i < (1 << N) - 1; i++) {
			visited = 0;
			for (int j = 0; j < N; j++) {
				idx = 1 << j;
				if ((i & idx) != 0)
				{
					visited |= V[j];
				}
			}
			if (visited == (1 << N) - 1)
			{
				int cnt = 0;
				for (int j = 0; j < N; j++)
				{
					idx = 1 << j;
					if ((i & idx) != 0)
					{
						cnt++;
					}
				}
				minV = min(cnt, minV);
			}
		}
		cout << minV << "\n";
	}
	return 0;
}

 


F. Cow Picnic (17분)

문제 링크

 

 

이 문제는 소들이 한 위치에서 모일 수 있는지 파악한 후 총 몇 개의 위치에서 모든 소들이 모일 수 있는지 출력하면 되는 문제다.

여기서 단방향 그래프이기 때문에 소들의 처음 위치에 따라서 방문할 수 있는 위치가 다르다.

그러므로 소들의 시작 위치를 고려해 어느 위치에 방문할 수 있는지 파악을 한 다음 모든 소들이 방문할 수 있는 지점을 계산하면 쉽게 풀 수 있는 문제다. 

 

더보기

구현

#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <set>
#include <algorithm>
#include <queue>
#include <unordered_map>
#include <set>
#include <map>
using namespace std;

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	int K, N, M;
	cin >> K >> N >> M;
	//k는 소 수, N은 목초지 수, M은 경로 수
	vector<int> cows(K);
	for (int i = 0; i < K; i++) {
		cin >> cows[i];
	}
	vector<vector<int>>graph(N+1);
	vector<vector<bool>>visited(N + 1, vector<bool>(N + 1,false));
	int st, ed;
	for (int i=0; i<M; i++)
	{
		cin >> st >> ed;
		graph[st].push_back(ed);
	}
	for (int i = 0; i < K; i++) {
		queue<int> q;
		visited[cows[i]][cows[i]] = true;
		q.push(cows[i]);
		while (!q.empty()) {
			int node = q.front();
			q.pop();
			for (int j = 0; j < graph[node].size(); j++) {
				if (!visited[cows[i]][graph[node][j]])
				{
					visited[cows[i]][graph[node][j]] = true;
					q.push(graph[node][j]);
				}
			}
		}
	}
	int Ans = 0;
	for (int i = 1; i <= N; i++) 
	{
		bool flag = true;
		for (int j = 0; j < K; j++) {
			if (!visited[cows[j]][i]) {
				flag = false;
				break;
			}
		}
		if (flag) {
			Ans += 1;
		}
	}
	cout << Ans;

	return 0;
}

 


G. 용액 (10분)

문제 링크

 

 

전형적인 투 포인터 문제다.

특성값이 0에 가장 가까운 용액을 만들기 위해 2개의 용액을 섞으므로 가장 특성값이 낮은 용액과 가장 높은 용액을 섞은 후 점차 용액을 바꿔나가면 된다.

오름차순으로 정렬이 된 상태므로 두 용액의 합이 0보다 크면 특성값이 큰 오른쪽 용액을 줄인다.

그러면 두 용액의 특성값이 줄어든다.

반대로 두 용액의 합이 0봐 작다면 특성값이 작은 왼쪽 용액을 오른쪽으로 옮긴다. 그러면 두 용액의 특성값이 늘어난다.

이러한 방법으로 탐색을 하면 고려하지 않아도 되는 경우를 고려하지 않아 O(N)으로 문제를 해결할 수 있다.

 

더보기

구현

#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <set>
#include <algorithm>
#include <queue>
#include <unordered_map>
#include <set>
#include <map>
using namespace std;
const int INF = 2087654321;
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	
	int N;
	cin >> N;
	vector<int> V(N);
	for (int i = 0; i < N; i++) {
		cin >> V[i];
	}
	int st = 0, ed=N-1;
	int minV=INF;
	int stV, edV, tmp;
	while(st<ed)
	{
		if (V[st] + V[ed] < 0) {
			tmp = abs(V[st] + V[ed]);
			if (minV > tmp) {
				minV = tmp;
				stV = V[st], edV = V[ed];
			}
			st++;
		}
		else if (V[st] + V[ed] > 0) 
		{
			tmp = V[st] + V[ed];
			if (minV > tmp) {
				minV = tmp;
				stV = V[st], edV = V[ed];
			}
			ed--;
		}
		else {
			cout << V[st] << " " << V[ed];
			return 0;
		}
	}
	cout << stV << " " << edV;

	return 0;
}

 


H. 나의 행렬곱셈 답사기 (8분)

문제 링크

 

이번에 푼 문제 중에 가장 간단하게 구현한 문제다.

행렬의 곱셈 수를 최적으로 곱셈한 방법과 최악으로 곱셈한 방법의 차이가 K가 되는 행렬을 찾으면 되는 문제다.

당연하게도 많은 경우가 있지만, 최대한 단순하게 표현하는게 K를 쉽게 찾을 수 있다.

그래서 행렬 3개를 이용해 K를 만들도록 했다.

행렬 A, B, C가 (a x b), (b x c), (c x d) 로 행렬이 구성됐다고 가정하자.

그러면 이 경우 행렬 곱셈 방법은 아래와 같이 두가지 밖에 없다.

 

1. AB를 먼저 계산 : (a x b x c) + (a x c x d)

2. BC를 먼저 계산 : (b x c x d) + (a x b x d)

 

여기서 계산을 단순하게 하기 위해서 b, c, d의 크기를 1로 하면 쉽게 문제를 해결할 수 있다.

그러면 1번과 2번의 계산값은 아래와 같이 단순하게 표현이 된다.

 

1. a + a

2. 1 + a

 

위 값을 통해 행렬 곱의 최악과 최선의 차이가 a-1 이므로 k = a-1이다.

그러므로 3개의 행렬이 k+1, 1, 1, 1 이면 행렬곱의 차이가 k가 되는 행렬을 찾을 수 있다.

 

 

더보기

구현

#include<iostream>
int main()
{
	int k;
	std::cin>>k;
	std::cout<<"3\n"<<k+1<<" 1 1 1";
	return 0;
}

 

[풀이 후기]

 

마지막 문제가 너무 쉬웠던 것 같다.

이번에는 111분으로 2시간 내에 모든 문제를 해결할 수 있었다.

풀 때 마다 영어 문제가 특히 오래걸리는데 다음번엔 영어 문제가 안나왔으면 좋겠다... ㅠㅠ

 

 

반응형

'Algorithm > BAEKJOON' 카테고리의 다른 글

[백준/C++] 색상환 (No. 2482)  (0) 2024.07.03
[백준/C++] RGB거리 2 (No. 17404)  (1) 2024.07.01
[백준/C++] 박성원 (No. 1086)  (0) 2024.06.27
[백준/C++] 외판원 순회 (No. 2098)  (0) 2024.06.24
[백준/C++] 집합 (No. 11723)  (0) 2024.06.23