※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※

 

이번에 볼 문제는 백준 25993번 문제인 Bellevue이다.
문제는 아래 링크를 확인하자.

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

 

한 방향으로의 시야각 최댓값을 찾을 때 주어지는 꺾이는 점만을 이용해 판단해도 충분함을 관찰하자. 해안가와 해당 점을 잇는 직선을 해안가를 원점으로 하는 직선들로 생각하면 이를 쉽게 이해할 수 있을 것이다.

 

왼쪽으로의 시야각과 오른쪽으로의 시야각의 최댓값 중 더 큰 값을 찾자.

 

글쓴이는 tanl값을 좌표를 이용해 계산 후 atan2l함수를 이용해 각도로 변환하여 문제를 해결하였다.

 

아래는 제출한 소스코드이다.

#include <iostream>
#include <cmath>
using namespace std;
typedef long double ld;

const ld PI = acosl(-1);
int N;
int P[50000][2];
ld X, Y;

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);

	cin >> N;
	for (int i = 0; i < N; i++) cin >> P[i][0] >> P[i][1];
	for (int k = 1; k + 1 < N; k++) {
		int dx = P[k][0] - P[0][0], dy = P[k][1];
		X = max(X, atan2l(dy, dx));
		dx = P[N - 1][0] - P[k][0];
		Y = max(Y, atan2l(dy, dx));
	}

	cout << fixed;
	cout.precision(10);
	cout << max(X, Y) * 180 / PI;
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 7804 // C++] Taxi!  (3) 2024.09.04
[BOJ 14265 // C++] 영선 수열  (3) 2024.09.03
[BOJ 23930 // C++] Parcels  (6) 2024.09.01
[BOJ 10349 // C++] Wet Tiles  (1) 2024.08.31
[BOJ 10425 // C++] 피보나치 인버스  (2) 2024.08.30

※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※

 

이번에 볼 문제는 백준 23930번 문제인 Parcels이다.
문제는 아래 링크를 확인하자.

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

 

먼저 각 칸에서 가장 가까운 delivery office까지의 거리를 multisource bfs를 이용해 계산해 두자.

 

각 칸의 좌표를 45도 회전시키고 원점으로부터의 거리를 \(\sqrt{2}\)배시켜 새로운 좌표에 대응시켜보자. 이 좌표계에서는 각 칸에 대하여 그 칸의 가장 가까운 delivery office까지의 거리가 어떤 정수 \(K\)에 대하여 그보다 작거나 같게 하기 위해 설치되어야 하는 새 office의 범위를 축에 평행항 변들로 이루어진 직사각형꼴로 나타낼 수 있다. 따라서 이 직사각형들의 교집합(에 포함되는 원래의 점 = 두 좌표의 합이 짝수인 점)의 존재 여부로 원하는 값이 \(K\) 이하가 될 수 있는지 여부를 판단할 수 있게 된다. 

 

\(K\)의 값을 이분 탐색으로 계산해 문제를 해결하자.

 

아래는 제출한 소스코드이다.

#include <iostream>
#include <queue>
using namespace std;

int R, C;
vector<pair<int, int>> vec[500];
int dist[250][250];
queue<pair<int, int>> que;
int dr[4] = {0,0,1,-1};
int dc[4] = {1,-1,0,0};
int LL, RR, mx;

int bnsearch() {
    LL = 0, RR = mx;
    while (LL < RR) {
        int mid = (LL + RR) / 2;
        int XL = -1000000007, XR = 1000000007, YL = -1000000007, YR = 1000000007;
        for (int k = mid + 1; k <= mx; k++) {
            for (auto &p:vec[k]) {
                XL = max(XL, p.first - mid);
                XR = min(XR, p.first + mid);
                YL = max(YL, p.second - mid);
                YR = min(YR, p.second + mid);
            }
        }
        if (XL <= XR && YL <= YR) {
            if (XL == XR && YL == YR && (abs(XL + YL) & 1)) LL = mid + 1;
            else RR = mid;
        }
        else LL = mid + 1;
    }
    return LL;
}

void bfs() {
    while (!que.empty()) {
        int r = que.front().first, c = que.front().second; que.pop();
        mx = max(mx, dist[r][c]);
        vec[dist[r][c] - 1].emplace_back(make_pair(r + c, c - r));
        for (int i = 0; i < 4; i++) {
            int rr = r + dr[i], cc = c + dc[i];
            if (rr < 0 || rr >= R || cc < 0 || cc >= C || dist[rr][cc]) continue;
            dist[rr][cc] = dist[r][c] + 1;
            que.push(make_pair(rr, cc));
        }
    }
}
void solve() {
    mx = 0;
    for (int r = 0; r < 500; r++) vec[r].clear();
    cin >> R >> C;
    for (int r = 0; r < R; r++) {
        for (int c = 0; c < C; c++) {
            char x; cin >> x;
            if (x == '1') dist[r][c] = 1, que.push(make_pair(r, c));
            else dist[r][c] = 0;
        }
    }
    bfs();
    cout << bnsearch() << '\n';
}

int T;

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    cin >> T;
    for (int t = 1; t <= T; t++) {
        cout << "Case #" << t << ": ";
        solve();
    }
}

 

랜덤 마라톤 · 코스 13 F번

728x90

'BOJ' 카테고리의 다른 글

[BOJ 14265 // C++] 영선 수열  (3) 2024.09.03
[BOJ 25993 // C++] Bellevue  (5) 2024.09.02
[BOJ 10349 // C++] Wet Tiles  (1) 2024.08.31
[BOJ 10425 // C++] 피보나치 인버스  (2) 2024.08.30
[BOJ 1206 // C++] 사람의 수  (2) 2024.08.29

※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※

 

이번에 볼 문제는 백준 10349번 문제인 Wet Tiles이다.
문제는 아래 링크를 확인하자.

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

 

T분 뒤에 어떤 칸이 젖어있으려면 어떤 물이 새는 곳까지의 거리가 T-1 이하여야 함을 관찰하자. 단 여기서 두 칸 사이의 거리는 한 칸에서 다른 칸으로 벽이 아닌 인접한 칸으로의 이동만을 이용하여 이동할 때 필요한 최소 이동횟수(단, 이동이 불가능하면 무한대)라 하자.

 

따라서 물이 새는 칸들을 시점으로 하는 multisource BFS를 돌려 각 칸이 젖기 위한 최소시간을 구해 문제를 쉽게 해결할 수 있다.

 

아래는 제출한 소스코드이다.

#include <iostream>
#include <vector>
#include <queue>
#include <utility>
using namespace std;

int R, C, T, L, W;

int dist[1002][1002];
queue<pair<int, int>> que;
int dr[4] = {0,0,1,-1};
int dc[4] = {1,-1,0,0};

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    while (cin >> R >> C >> T >> L >> W) {
        for (int r = 1; r <= R; r++) {
            for (int c = 1; c <= C; c++) {
                dist[r][c] = 0;
            }
        }
        while (L--) {
            int r, c; cin >> r >> c;
            dist[r][c] = 1;
            que.push(make_pair(r, c));
        }
        while (W--) {
            int r1, c1, r2, c2; cin >> r1 >> c1 >> r2 >> c2;
            if (r1 == r2) {
                if (c1 > c2) swap(c1, c2);
                for (int c = c1; c <= c2; c++) dist[r1][c] = 1000000007;
            }
            else if (c1 == c2) {
                if (r1 > r2) swap(r1, r2);
                for (int r = r1; r <= r2; r++) dist[r][c1] = 1000000007;
            }
            else if (r2 - r1 == c2 - c1) {
                if (r1 > r2) swap(r1, r2), swap(c1, c2);
                for (int r = r1, c = c1; r <= r2; r++, c++) dist[r][c] = 1000000007;
            }
            else {
                if (r1 > r2) swap(r1, r2), swap(c1, c2);
                for (int r = r1, c = c1; r <= r2; r++, c--) dist[r][c] = 1000000007;
            }
        }

        while (!que.empty()) {
            int r = que.front().first, c = que.front().second; que.pop();
            for (int i = 0; i < 4; i++) {
                int rr = r + dr[i], cc = c + dc[i];
                if (rr < 1 || rr > R || cc < 1 || cc > C || dist[rr][cc]) continue;
                dist[rr][cc] = dist[r][c] + 1;
                que.push(make_pair(rr, cc));
            }
        }
        
        int ans = 0;
        for (int r = 1; r <= R; r++) {
            for (int c = 1; c <= C; c++) {
                if (dist[r][c] && dist[r][c] <= T) ans++;
            }
        }
        cout << ans << '\n';
    }
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 25993 // C++] Bellevue  (5) 2024.09.02
[BOJ 23930 // C++] Parcels  (6) 2024.09.01
[BOJ 10425 // C++] 피보나치 인버스  (2) 2024.08.30
[BOJ 1206 // C++] 사람의 수  (2) 2024.08.29
[BOJ 32065 // C++] Short Function  (0) 2024.08.28

※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※

 

이번에 볼 문제는 백준 10425번 문제인 피보나치 인버스이다.
문제는 아래 링크를 확인하자.

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

 

적절한 \(10^K\)로 첫 10만개의 피보나치 수를 나눈 나머지를 얻어보면 (첫 두 수를 제외하고) 이 값들이 서로 다름을 확인할 수 있다.

 

따라서 이를 이용해 첫 10만개의 수를 \(10^K\)로 나눈 나머지를 map 등을 이용해 순서와 대응시켜 문제를 해결할 수 있다.

 

아래는 제출한 소스코드이다.

#include <iostream>
#include <map>
using namespace std;
typedef long long ll;

int T;
ll A = 1, B = 1;
map<ll, int> mp;

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    for (int k = 2; k < 100001; k++) {
        A += B;
        swap(A, B);
        if (B > 99999999999999999LL) B -= 100000000000000000LL;
        mp[A] = k;
    }
    
    cin >> T;
    while (T--) {
        string s; cin >> s;
        ll val = 0;
        for (auto &l:s) {
            val = val * 10 + (l - '0');
            val %= 100000000000000000LL;
        }
        cout << mp[val] << '\n';
    }
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 23930 // C++] Parcels  (6) 2024.09.01
[BOJ 10349 // C++] Wet Tiles  (1) 2024.08.31
[BOJ 1206 // C++] 사람의 수  (2) 2024.08.29
[BOJ 32065 // C++] Short Function  (0) 2024.08.28
[BOJ 24539 // C++] 암호 해독  (0) 2024.08.27

※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※

 

이번에 볼 문제는 백준 1206번 문제인 사람의 수이다.
문제는 아래 링크를 확인하자.

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

 

어떤 평균점수가 주어져도 10000명의 사람이 있다면 모든 평균 점수가 나오게끔 사람들이 투표할 수 있음을 관찰하자. 따라서, 1부터 10000까지 사람의 수로 가능한 수치를 하나하나 확인해나가는 완전탐색 풀이로 문제를 충분히 해결할 수 있다.

 

이 문제의 경우 버림을 통해 소수의 값을 계산함에 유의하자. Long Division(장제법; 초등학생들이 나눗셈의 몫과 나머지 구하던 그 방법)을 직접 구현하면 문제가 요구하는 값을 오차 없이 계산할 수 있다.

 

아래는 제출한 소스코드이다.

#include <iostream>
#include <string>
using namespace std;

int N;
int A[50];
string s;

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);

	cin >> N;
	for (int i = 0; i < N; i++) {
		cin >> s;
		if (s.length() == 6) continue;
		A[i] = (s.front() - '0') * 1000 + stoi(s.substr(2, 3));
	}
	for (int k = 1; k < 10001; k++) {
		bool chk = 1;
		for (int i = 0; i < N; i++) {
			int L = 0, R = k * 10;
			while (L <= R) {
				int mid = (L + R) / 2;
				int val = 0;
				for (int _ = 0; _ < 4; _++) {
					val = val * 10 + mid / k;
					mid %= k;
					mid *= 10;
				}
				if (val < A[i]) L = (L + R) / 2 + 1;
				else if (val > A[i]) R = (L + R) / 2 - 1;
				else goto BREAK1;
			}
			chk = 0;
			goto BREAK2;
			BREAK1:
			1;
		}
		BREAK2:
		if (chk) {
			cout << k;
			return 0;
		}
	}
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 10349 // C++] Wet Tiles  (1) 2024.08.31
[BOJ 10425 // C++] 피보나치 인버스  (2) 2024.08.30
[BOJ 32065 // C++] Short Function  (0) 2024.08.28
[BOJ 24539 // C++] 암호 해독  (0) 2024.08.27
[BOJ 13733 // C++] Square Deal  (0) 2024.08.26

※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※

 

이번에 볼 문제는 백준 32065번 문제인 Short Function이다.
문제는 아래 링크를 확인하자.

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

 

주어진 식이 값을 곱해나가는 규칙이 마치 sparse table(희소 테이블)의 값을 채워나가는 과정과 유사해보이지 않는가?

 

위 관찰을 이용하면, 각 A[i]의 값은 결국 주어진 배열이 끝없이 반복되는 수열의 i번째 항부터 시작되는 길이 \(2^K\)의 배열에 적힌 수의 곱이 됨을 알 수 있다. 대충 \(2^K\)을 \(N\)으로 나눈 몫만큼 배열 전체의 곱을 곱하고, 나머지만큼 배열의 구간곱을 구해 둘을 곱하는 것으로 원하는 값을 계산하자.

 

그런데 이 값을 그냥 계산하기에는 \(2^K\)의 값이 너무 커서 계산이 어렵다. 구하고자 하는 값이 소수 998244353으로 나눈 나머지이므로, 배열 전체를 998244352회 곱한 값이 1이 됨을 이용해 이 과정을 가능하게 만들자. 즉, \(2^K\)을 \(N\)으로 나눈 몫 대신 이 값을 998244352로 나눈 나머지를 이용해도 문제의 답이 같게 나옴을 이용하자. 이는 998244353이 소수이고 배열을 구성하는 각 원소가 998244353의 배수가 아니므로 가능하다.

 

아래는 제출한 소스코드이다.

#include <iostream>
using namespace std;
typedef __int128 lll;

int tmp;
lll MOD = 998244353, NMOD, ansconst, qrylen;
lll N, K, total = 1, A[100001];
lll totalcnt;

lll seg[262145];
lll init(int L, int R, int sI) {
	if (L < R) return seg[sI] = init(L, (L + R) / 2, sI * 2) * init((L + R) / 2 + 1, R, sI * 2 + 1) % MOD;
	return seg[sI] = A[L];
}
lll qry(int L, int R, int qL, int qR, int sI) {
	if (R < qL || qR < L) return 1;
	if (qL <= L && R <= qR) return seg[sI];
	return qry(L, (L + R) / 2, qL, qR, sI * 2) * qry((L + R) / 2 + 1, R, qL, qR, sI * 2 + 1) % MOD;
}

lll bexp(lll X, lll KK) {
	lll ret = 1;
	while (KK) {
		if (KK & 1) ret = ret * X % MOD;
		KK >>= 1, X = X * X % MOD;
	}
	return ret;
}

lll func(lll x, lll M) { // 2^x의 mod M을 계산
	lll ret = 1, val = 2;
	while (x) {
		if (x & 1) ret = ret * val % M;
		val = val * val % M;
		x >>= 1;
	}
	return ret;
}

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);

	cin >> tmp; N = tmp;
	cin >> tmp; K = tmp;
	NMOD = N * (MOD - 1);
	for (int i = 1; i <= N; i++) {
		cin >> tmp, A[i] = tmp;
		total = total * A[i] % MOD;
	}
	totalcnt = func(K, NMOD) / N;
	ansconst = bexp(total, totalcnt);
	qrylen = func(K, N);

	if (!qrylen) {
		for (int i = 1; i <= N; i++) cout << (int)ansconst << ' ';
		return 0;
	}
	
	init(1, N, 1);
	for (int i = 1; i <= N; i++) {
		int L = i, R = i + qrylen - 1;
		if (R <= N) cout << (int)(ansconst * qry(1, N, L, R, 1) % MOD) << ' ';
		else cout << (int)(ansconst * (qry(1, N, L, N, 1) * qry(1, N, 1, R - N, 1) % MOD) % MOD) << ' ';
	}
}

 

랜덤 마라톤 · 코스 12 H번

728x90

'BOJ' 카테고리의 다른 글

[BOJ 10425 // C++] 피보나치 인버스  (2) 2024.08.30
[BOJ 1206 // C++] 사람의 수  (2) 2024.08.29
[BOJ 24539 // C++] 암호 해독  (0) 2024.08.27
[BOJ 13733 // C++] Square Deal  (0) 2024.08.26
[BOJ 17797 // C++] Dome Construction  (0) 2024.08.25

+ Recent posts