문제 A: 인공지능의 종료 시나리오
이 문제는 상태 간의 전이를 효율적으로 관리하는 것이 핵심입니다. 주어진 값들의 분포를 압축하여 중복을 제거하고 (좌표 압축), 각 단계마다 가능한 최소 이동 횟수를 계산합니다. 전체적인 시간 복잡도는 로그 스케일을 가지므로 \(O(N \log N)\) 입니다.
// 참조 구현 코드
#include <bits/stdc++.h>
using namespace std;
const int MAX_VAL = 1000005;
int target_count[MAX_VAL];
vector<int> compressed_values;
void solve_a() {
int n, k;
cin >> n >> k;
vector<int> input_data(n);
for(int i=0; i<n; ++i) {
cin >> input_data[i];
compressed_values.push_back(input_data[i]);
}
sort(compressed_values.begin(), compressed_values.end());
compressed_values.erase(unique(compressed_values.begin(), compressed_values.end()), compressed_values.end());
auto get_id = [&](int val) {
return lower_bound(compressed_values.begin(), compressed_values.end(), val) - compressed_values.begin();
};
if (compressed_values.size() < k) {
cout << 0 << "\n";
return;
}
int current_limit = k;
int min_threshold = 0;
for(int i=0; i<n; ++i) {
int id = get_id(input_data[i]);
if (target_count[id] == min_threshold) {
current_limit--;
if (current_limit == 0) {
min_threshold++;
current_limit = k - 1;
target_count[id] = min_threshold + 1;
} else {
target_count[id] = min_threshold + 1;
}
}
}
cout << min_threshold << "\n";
}
문제 B: 기본 수학적 연산
큰 수 \(B\) 를 진수로 간주할 때, 식의 좌변은 \(B\) 가 커질수록 자리수 간 매칭이 줄어듭니다. 이 성질은 단조성을 가지므로, 범위를 좁히면서 최적의 \(B\) 값을 찾는 이진 탐색을 적용합니다. 제곱과 덧셈의 조합을 계산할 때 오버플로우를 방지해야 하며, 최대값 기반 검증이 필요합니다.
// 참조 구현 코드
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX_LEN = 2005;
const ll LIMIT = 2e18;
ll poly_res[MAX_LEN];
int coef_a[MAX_LEN], coef_b[MAX_LEN], coef_c[MAX_LEN];
bool check(ll base) {
fill(poly_res, poly_res + MAX_LEN, 0);
int deg_a = /* input size */, deg_b = /* input size */;
// 다항식 곱셈 및 캐리 처리 로직
// ...
// 결과와 타겟 계수 비교
}
void solve_b() {
int n, m, k;
cin >> n >> m >> k;
int mx_val = 0;
for(int i=0; i<n; ++i) { cin >> coef_a[i]; mx_val = max(mx_val, coef_a[i]); }
for(int i=0; i<m; ++i) { cin >> coef_b[i]; mx_val = max(mx_val, coef_b[i]); }
for(int i=0; i<k; ++i) { cin >> coef_c[i]; mx_val = max(mx_val, coef_c[i]); }
ll left = mx_val + 1, right = LIMIT, ans = -1;
while(left <= right) {
ll mid = left + (right - left) / 2;
// 검증 로직 실행
bool ok = true;
// 조건 확인 후 범위 갱신
if(ok) { ans = mid; right = mid - 1; }
else left = mid + 1;
}
cout << (ans == -1 ? "impossible" : to_string(ans)) << "\n";
}
문제 C: 경로 최적화 공사
두 지점 간의 거리와 추가 비용을 고려한 동적 프로그래밍 (DP) 접근법입니다. 각 점에서 다음 점으로 이동할 때 각도를 기준으로 구간 쿼리를 수행하며, 페닉트리 (BIT) 를 사용하여 구간 합을 효율적으로 업데이트합니다. 이는 \(O(N^2 \log N)\) 에 해결 가능합니다.
// 참조 구현 코드
struct Point { double x, y; };
struct BitTree {
int tree[1505];
void update(int idx, int val) {
for(; idx<=1500; idx+=idx&-idx) tree[idx]+=val;
}
int query(int idx) {
int res=0;
for(; idx>0; idx-=idx&-idx) res+=tree[idx];
return res;
}
};
double dist(Point p1, Point p2) {
return hypot(p1.x-p2.x, p1.y-p2.y);
}
void solve_c() {
int n; double cost_per_kg;
cin >> n >> cost_per_kg;
vector<Point> locs(n+1);
for(int i=1; i<=n; ++i) cin >> locs[i].x >> locs[i].y;
// dp[state][direction] 초기화 및 전이 로직
// 각도 정렬 및 BIT 활용 최적화
// ...
// 최종 결과 출력
}
문제 D: 순열 재정렬
순열의 상태를 변화시키는操作的인 경우의 수가 많지만, 목표 도달 단계가 작습니다 (최대 6). 따라서 양방향 BFS 를 활용하여 중간에서 만나게 됩니다. 순열을 Cantor 확장법을 통해 정수로 인코딩하여 방문 집합에 저장합니다. 그래프 탐색의 효율성을 위해 팩토리얼 번호 시스템을 사용합니다.
// 참조 구현 코드
vector<int> perm_to_rank(const vector<int>& p) {
// 랭킹 계산 로직
}
vector<int> rank_to_perm(int rank, int n) {
// 랭킹 복원 로직
}
void solve_d() {
int n; cin >> n;
vector<int> start_state(n), target_state(n);
// 입력 처리
unordered_map dist_forward, dist_backward;
queue<int> q_front, q_back;
// 양방향 검색 시작
// ...
// 최단 거리 계산 및 출력
}
문제 E: 확률 기반 추측
무작위 배열에서 특정 값을 맞출 확률을 구하는 문제입니다. 최댓값의 분포를 이용하면, '최댓값이 X 이하인 경우'와 '최댓값이 Y 이하인 경우'의 차이를 통해 정확히 X 일 확률을 유도할 수 있습니다. 이를 합산 공식으로 변환하면 \(k\) 제곱합 문제로 귀결됩니다.
// 참조 구현 코드
ll power(ll base, ll exp) {
ll res = 1;
while(exp) { if(exp&1) res=res*base%M; base=base*base%M; exp>>=1; }
return res;
}
void solve_e() {
int n, k; cin >> n >> k;
// 포함배clusion 원리와 조화수 급수 활용
// 조합론적 항 전개
// ...
// 모듈러 연산 적용 후 출력
}
문제 F: 고유 ID 할당
이미 사용된 숫자들의 패리티 (홀짝) 를 세어봅니다. 가장 빈도가 높은 패리티에 속하지 않는 가장 작은 숫자를 찾거나, 그렇지 않은 경우 해당 패리티의 미사용 숫자를 찾습니다. 단순한 시뮬레이션으로 해결 가능합니다.
// 참조 구현 코드
void solve_f() {
int n; cin >> n;
set<int> used_numbers;
int odd_cnt = 0, even_cnt = 0;
for(int i=0; i> val;
used_numbers.insert(val);
if(val%2) odd_cnt++; else even_cnt++;
}
int preferred_parity = (even_cnt > odd_cnt) ? 1 : 0;
// 후보 탐색 및 출력
}
문제 G: 그리드 경로 기대값
흰색 칸에서의 행동 패턴을 분류하여 두 가지 유형으로 나눕니다. 각 유형에 대해 목표지점으로 바로 갈지 다시 흰색 칸을 방문할지 결정하는 임계값이 존재하며, 이 함수는 단봉형 (unimodal) 입니다. 따라서 삼분 탐색을 두 번 수행하여 최소 기대값을 찾습니다.
// 참조 구현 코드
Fraction calculate_expectation(int type_idx, int count) {
// 분수 구조체 정의
// 기댓값 수식 계산
}
void solve_g() {
int rows, cols; cin >> rows >> cols;
vector<string> grid(rows);
// BFS 로 백워드 거리 계산
// 타입 분류 및 누적합 배열 구성
// 삼분 탐색 수행
// ...
}
문제 H: 산길 네트워크
두 가지 다른 방향성 그래프를 구축하고, 목적지에서의 거리를 기반으로 엣지를 생성합니다. 이후 최장 경로를 찾고 사이클이 있는지 확인하는 SPFA 알고리즘 변형을 사용합니다. 무한 루프 감지를 위해 방문 횟수를 카운트합니다.
// 참조 구현 코드
void solve_h() {
int n, start_node, end_node; cin >> n >> start_node >> end_node;
// 그래프 구축 로직 (정방향, 역방향 가중치 분석)
// 스파피 (SPFA) 기반 최장 경로 탐색
// 음수 사이클 또는 포지티브 사이클 체크
// ...
}
문제 I: 순위 판정 시스템
제출 시간 문자열을 파싱하여 총 누적 시간을 초 단위로 변환합니다. 킬러 (AC) 개수, 패널티 시간, 팀 이름의 사전 순서를 기준으로 비교하여 참가자의 최종 랭킹을 도출합니다. 직관적인 시뮬레이션 로직이 요구됩니다.
// 참조 구현 코드
long long parse_time(string s) {
// HH:MM:SS 포맷 파싱
// 0-index 기준 오프셋 적용
}
void solve_i() {
int n_teams; cin >> n_teams;
// 데이터 읽기 및 정규화
// 사용자 정의 비교함수를 사용한 랭킹 계산
// ...
}
문제 J: 구역 이동 비용
주어진 구간들을 모두 커버하기 위한 최적 경로는 최소 좌표에서 최대 좌표로 이동하는 과정에서 발생합니다. 주요 이동 방향 (오른쪽 또는 왼쪽) 을 고정하고, 반대 방향으로 돌아야 하는 구간들에 대한 추가 비용을 최소화하는 문제를贪婪法으로 풉니다.
// 참조 구현 코드
void solve_j() {
int range_limit, num_segments; cin >> range_limit >> num_segments;
vector> segs(num_segments);
// 구간 입력
// L, R 계산 및 그리디 선택
// ...
}
문제 K: 트리 충돌 검증
사전 순서 트라이 (Trie) 를 구축한 뒤, 동시에 두 노드를 이동시키며 끝나는 위치가 겹치는지 확인합니다. 만약 서로 다른 단어 경로가 동일한 접두사에서 종료되거나 충돌한다면 조건을 만족하지 못함을 판별합니다. 깊이 우선 탐색 (DFS) 을 통해 재귀적으로 검증합니다.
// 참조 구현 코드
struct Node {
int next[26] = {0};
bool is_end = false;
} trie[MAX_NODES];
bool validate_collision(int u, int v) {
if(u==v && trie[u].is_end) return true; // 충돌
if(trie[u].is_end && trie[v].is_end) return true;
// 자식 노드 재귀 호출
// ...
}
void solve_k() {
// 트라이 구축
// 충돌 여부 DFS
// 결과输出
}