- 프래머스 - 다단계 칫솔 판매
더보기
#include <string> #include <vector> #include <unordered_map> using namespace std; constexpr int PRICE = 100; vector<int> solution(vector<string> enroll, vector<string> referral, vector<string> seller, vector<int> amount) { vector<int> answer; answer.resize(enroll.size(), 0); unordered_map<string, int> IDs; int ID = 0; for(auto en : enroll) IDs[en] = ID++; vector<int> parents(enroll.size()); //추천인을 다단계 tree상의 부모로 간주 for(int i=0;i<enroll.size();++i) { if(referral[i] == "-") parents[i] = i; else { int parentID = IDs[referral[i]]; parents[i] = parentID; } } for(int i=0;i<seller.size();++i) { int sellerID = IDs[seller[i]]; int profit = PRICE * amount[i]; while(profit>0) { int parentID = parents[sellerID]; int royalty = profit / 10; profit -= royalty; answer[sellerID] += profit; if(parentID == sellerID) break; //다음 루프에 넘김 profit = royalty; sellerID = parentID; } } return answer; }
- 백준 11729 - 하노이 탑 이동 순서
더보기
#include <iostream> #include <cmath> using namespace std; void hanoi(int n, int from, int to, int temp) { if (n == 0) return; hanoi(n - 1, from, temp, to); cout << from << ' ' << to << '\n'; hanoi(n - 1, temp, to, from); } int main() { int n; cin >> n; cout << (int)pow(2,n) - 1 << '\n'; hanoi(n, 1, 3, 2); }
- 백준 - 3653 - 영화 수집
더보기
#include <iostream> #include <vector> using namespace std; class BufferedFenwickTree { public: BufferedFenwickTree(int n, int m) : tree_size_{ n+m+1 }, n_{n}, m_{m}, cur_idx_{0} { dvd_pos_.resize(n + 1, 0); tree_.resize(tree_size_ + 1, 0); for (int i = 1; i <= n; ++i) { dvd_pos_[i] = i + m; Add(i + m, 1); } } public: int Watch(int dvd) { const int dvd_pos = dvd_pos_[dvd]; const int ret = Sum(dvd_pos) - 1; dvd_pos_[dvd] = m_ - cur_idx_; cur_idx_++; Add(dvd_pos, -1); Add(dvd_pos_[dvd], 1); return ret; } private : int Sum(int pos) { int result = 0; while (pos > 0) { result += tree_[pos]; pos -= (pos & -pos); } return result; } void Add(int pos, int val) { while (pos <= tree_size_) { tree_[pos] += val; pos += (pos & -pos); } } private: int tree_size_, n_, m_, cur_idx_; vector<int> tree_, dvd_pos_; }; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); int num_test_case; cin >> num_test_case; while (num_test_case-- > 0) { int n, m; cin >> n >> m; BufferedFenwickTree bft(n,m); for (int i = 1; i <= m; ++i) { int dvd; cin >> dvd; cout << bft.Watch(dvd) << ' '; } cout << "\n"; } return 0; }
- 백준 2934 - LRH 식물 (펜윅트리)
더보기
#include <iostream> #include <vector> using namespace std; using LL = long long; class BIT //binary-indexed(fenwick) tree { public: BIT() = delete; explicit BIT(int n) : size_{ n } { tree_.resize(n + 1, 0); } LL PlantAndGetFlowers(int L, int R) { LL flowers_left = GetValue(L); LL flowers_right = GetValue(R); AddRange(L, L, -flowers_left); AddRange(R, R, -flowers_right); AddRange(L + 1, R - 1, 1); return flowers_left + flowers_right; } private: void AddRange(int left, int right, LL val) { if (left > right) return; AddValueFromStart(right, val); AddValueFromStart(left - 1, -val); } void AddValueFromStart(int dest_pos, LL val) { int idx = dest_pos; while(idx > 0) { tree_[idx] += val; idx &= idx - 1; } } LL GetValue(int pos) { int idx = pos; LL ret = 0; while(idx <= size_) { ret += tree_[idx]; idx += (idx & -idx); } return ret; } private: vector<LL> tree_; int size_; }; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); int N, L, R; cin >> N; BIT bit{ 100000 }; for(int i=0;i<N;++i) { cin >> L >> R; cout << bit.PlantAndGetFlowers(L, R) << "\n"; } return 0; }
- 백준 1766 - 문제집 (위상 정렬)
더보기
#include <vector> #include <iostream> #include <queue> #include <algorithm> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); int N, M; cin >> N >> M; vector<vector<int>> graph(N+1); vector<int> indegrees(N + 1, 0); vector<int> answer; while(M-->0) { int A, B; cin >> A >> B; graph[A].emplace_back(B); indegrees[B]++; } priority_queue<int, vector<int>, greater<>> pq; for(int i=1;i<=N;++i) { if (indegrees[i] == 0) pq.emplace(i); } while(false == pq.empty()) { int cur_num = pq.top(); pq.pop(); answer.emplace_back(cur_num); std::for_each(graph[cur_num].begin(), graph[cur_num].end(), [&indegrees, &pq](int next){if (--indegrees[next] == 0) pq.emplace(next);}); } std::for_each(answer.begin(), answer.end(), [](int ans) {cout << ans << ' '; }); return 0; }
- 백준 2261 - 가장 가까운 두 점 (분할정복, 스위핑)
더보기
#include <vector> #include <iostream> #include <algorithm> #include <set> #include <cmath> using namespace std; struct Point { public: Point(int x, int y) : x{ x }, y{ y }{} int SqrDist(Point & other) const { int dx = this->x - other.x; int dy = this->y - other.y; return dx * dx + dy * dy; } //x를 기준으로 정렬함. bool operator < (const Point & other) const { return OrderByX(*this, other); } static bool OrderByY(const Point& p1, const Point& p2) { if (p1.y < p2.y) return true; if (p1.y == p2.y && p1.x < p2.x) return true; return false; } static bool OrderByX(const Point& p1, const Point& p2) { if (p1.x < p2.x) return true; if (p1.x == p2.x && p1.y < p2.y) return true; return false; } public: int x, y; }; int main() { int N; cin >> N; vector<Point> points; points.reserve(N); for(int i=0;i<N;++i) { int x, y; cin >> x >> y; points.emplace_back(x, y); } //y를 기준으로 정렬함. sort(points.begin(), points.end(), Point::OrderByY); set<Point> s; s.insert(points[0]); s.insert(points[1]); int dist = points[0].SqrDist(points[1]); int startIdx = 0; for (int i = 2; i < N; ++i) { //y가 이미 거리보다 차이 많이나면 목록에서 제거 while (startIdx < i) { int dy = points[i].y - points[startIdx].y; if(dy*dy > dist) s.erase(points[startIdx++]); else break; } //x 좌표가 거리 사이에 있는 모든 좌표 순회하며 거리 업데이트 const auto lb = s.lower_bound({ points[i].x - static_cast<int>(sqrt(dist)), -INT32_MAX }); const auto ub = s.upper_bound({ points[i].x + static_cast<int>(sqrt(dist)), INT32_MAX }); for (auto j = lb; j != ub; ++j) { auto curP = *j; dist = min(dist, points[i].SqrDist(curP)); } s.insert(points[i]); } cout << dist; }
- 백준 1939 - 중량 제한 (파라메트릭 서치)
더보기
#include <iostream> #include <vector> #include <unordered_map> #include <queue> #include <cstring> #include <set> #include <algorithm> using namespace std; constexpr int MAX_N = 10001; int N, M, S, E; //pair<int,int> 의 hash funciton struct hash_pair { std::size_t operator() (const pair<int, int>& p) const { return (p.first * MAX_N) + p.second; } }; //TODO : 섬 A,B 에 다리가 여러개인 경우 하나만 저장하려고 이렇게 했는데 그냥 다 검사하는게 빠름 unordered_map<pair<int,int>, int, hash_pair> weights; //TODO : 다리 목록 순회할때 weight 로 정렬해주면 최적화 가능. vector<vector<int>> bridges; bool bfs_visit(int weight) { bool enqueued[MAX_N]; memset(enqueued, 0, sizeof(enqueued)); queue<int> q; q.emplace(S); while(false == q.empty()) { int cur = q.front(); q.pop(); for(auto next : bridges[cur]) { if (enqueued[next] == true) continue; auto bridge = cur < next ? std::make_pair(cur, next) : std::make_pair(next, cur); if(weights[bridge] >= weight) { if (next == E) return true; q.emplace(next); enqueued[next] = true; } } } return false; } int main() { cin >> N >> M; bridges.resize(N + 1); while(M-->0) { int A, B, C; cin >> A >> B >> C; if (A > B) swap(A, B); auto bridge = std::make_pair(A, B); //새로 추가됨 if(0 == weights[bridge]) { bridges[A].emplace_back(B); bridges[B].emplace_back(A); } if (C > weights[bridge]) weights[bridge] = C; } cin >> S >> E; int answer = 0; int l = 1, r = 1000000000; while(l<=r) { int mid = (l + r) / 2; if(bfs_visit(mid)) { answer = mid; l = mid + 1; } else { r = mid - 1; } } cout << answer << endl; return 0; }
- 백준 9250 - 문자열 집합 판별 (아호코라식)
더보기
#include <iostream> #include <vector> #include <string> #include <queue> using namespace std; struct TrieNode { public: TrieNode() { nexts.resize(26, nullptr); } ~TrieNode() { for(auto node : nexts) { if (node != nullptr) delete(node); } } public: vector<TrieNode*> nexts; TrieNode* fail = nullptr; bool is_end = false; }; void add_to_trie(TrieNode & root, string && str) { TrieNode * cur_node = &root; for (char c : str) { const int idx = c - 'a'; if(cur_node->nexts[idx] == nullptr) cur_node->nexts[idx] = new TrieNode(); cur_node = cur_node->nexts[idx]; //이미 종결된 다른 문자를 포함한 경우 더 저장할 필요 x if (cur_node->is_end) return; } cur_node->is_end = true; } void set_fail_trie(TrieNode* root) { queue<TrieNode*> q; for(auto next : root->nexts) { if (next == nullptr) continue; next->fail = root; q.emplace(next); } while(false == q.empty()) { auto cur_node = q.front(); q.pop(); auto nexts = cur_node->nexts; for(int i=0;i<26;++i) { auto next_node = nexts[i]; if (next_node == nullptr) continue; next_node->fail = root; auto prevs_fail_node = cur_node->fail; while(prevs_fail_node!=nullptr) { if (prevs_fail_node->nexts[i] != nullptr) { next_node->fail = prevs_fail_node->nexts[i]; break; } prevs_fail_node = prevs_fail_node->fail; } //fail_node가 종결이면 나도 종결임. if (next_node->fail->is_end) next_node->is_end = true; q.emplace(next_node); } } } string contains(string && str, TrieNode* root) { TrieNode * cur_node = root; for(auto c : str) { int idx = c - 'a'; while(true) { if (cur_node->nexts[idx] != nullptr) { cur_node = cur_node->nexts[idx]; break; } if (cur_node == root) break; cur_node = cur_node->fail; } if(cur_node->is_end) return "YES\n"; } return "NO\n"; } int main() { cin.tie(nullptr); cout.tie(nullptr); ios::sync_with_stdio(false); int N; cin >> N; TrieNode root; for(int i=0;i<N;++i) { string str_in_s; cin >> str_in_s; add_to_trie(root, std::move(str_in_s)); } set_fail_trie(&root); int Q; cin >> Q; for(int i=0;i<Q;++i) { string str_in_q; cin >> str_in_q; cout << contains(std::move(str_in_q), &root); } return 0; }
- 프로그래머스 - 퍼즐 조각 채우기
더보기
//https://programmers.co.kr/learn/courses/30/lessons/84021 #include <vector> #include <unordered_map> #include <queue> using namespace std; /* * /////////////////////////////////////////////////////////////////////////////////////////////////////// * // * 모양은 최대 6칸이므로, 하나의 int로 정의할 수 있다. // * 하나의 모양은 높이, 너비를 각각 3비트씩 할당하고 나머지 모양을 1비트씩 할당해서 만들 수 있다. // * 모양은 key로 구분할 수 있다. // * key는 모양을 회전시켜서 얻을 수 있는 int값의 최소값이다. // * // *//////////////////////////////////////////////////////////////////////////////////////////////////////// unordered_map<int, int> shape_keys; vector<pair<int,int>> dirs = { {0,1}, {0,-1},{1,0},{-1,0} }; //shape로 key를 얻어옴. //shape 맨 앞에 3비트씩 각각 높이, 너비를 저장 //그 후로 각 shape마다 1비트씩 값 저장 int GetShapeKey(const vector<vector<bool>> & shape) { int h = shape.size(); int w = shape[0].size(); int key = 0; key += h; key = key << 3; key += w; key = key << 3; for(int i=0;i<h;++i) for(int j=0;j<w;++j) { key += shape[i][j]; key = key << 1; } return key; } //시계방향으로 90도 회전시킴 void Rotate(vector<vector<bool>> & shape) { int h = shape.size(); int w = shape[0].size(); vector<vector<bool>> newShape(w, vector<bool>(h)); for (int i = 0; i < h; ++i) for (int j = 0; j < w; ++j) newShape[j][h - 1 - i] = shape[i][j]; shape = newShape; } //원시적인 형태의 shape 구함 vector<pair<int, int>> GetPrimitiveShape(vector<vector<int>> board, int blockVal, int y, int x) { int h = board.size(); int w = board[0].size(); int notBlockVal = blockVal == 0 ? 1 : 0; vector<pair<int, int>> points; board[y][x] = notBlockVal; points.emplace_back(y, x); queue<pair<int, int>> q; q.emplace(y, x); while (false == q.empty()) { auto curPoint = q.front(); q.pop(); for (auto dir : dirs) { int newX = curPoint.second + dir.second; int newY = curPoint.first + dir.first; if (newX < 0 || newX >= w || newY < 0 || newY >= h) continue; if (board[newY][newX] == blockVal) { points.emplace_back(newY, newX); q.emplace(newY, newX); board[newY][newX] = notBlockVal; } } } return points; } //다듬어진 형태의 shape로 변환 vector<vector<bool>> ToShape(const vector<pair<int, int>> & points) { int minX = points[0].second; int minY = points[0].first; int maxX = points[0].second; int maxY = points[0].first; for (auto point : points) { int x = point.second; int y = point.first; if (y < minY) minY = y; else if (y > maxY) maxY = y; if (x < minX) minX = x; else if (x > maxX) maxX = x; } vector<vector<bool>> shape(maxY - minY + 1, vector<bool>(maxX - minX + 1, 0)); for (auto point : points) { int x = point.second - minX; int y = point.first - minY; shape[y][x] = true; } return shape; } int solution(vector<vector<int>> game_board, vector<vector<int>> table) { int h = game_board.size(); int w = game_board[0].size(); for(int i=0;i<h;++i) { for(int j=0;j<w;++j) { if(game_board[i][j] == 0) { auto primitive = GetPrimitiveShape(game_board, 0, i, j); auto shape = ToShape(primitive); int key = GetShapeKey(shape); for(int i=0;i<3;++i) { Rotate(shape); int newKey = GetShapeKey(shape); if (newKey < key) key = newKey; } shape_keys[key]++; } } } int match_cnt = 0; for (int i = 0; i < h; ++i) { for (int j = 0; j < w; ++j) { if (table[i][j] == 1) { auto primitive = GetPrimitiveShape(table, 1, i, j); auto shape = ToShape(primitive); int key = GetShapeKey(shape); for (int i = 0; i < 3; ++i) { Rotate(shape); int newKey = GetShapeKey(shape); if (newKey < key) key = newKey; } if(shape_keys[key] > 0) { shape_keys[key]--; match_cnt++; } } } } return match_cnt; }
- 백준 3033 - 가장 긴 문자열 (라빈 카프 알고리즘)
더보기
#include <iostream> #include <cstring> #include <vector> #include <cmath> using namespace std; class RabinKarpString { public: RabinKarpString(string && s) { str_ = std::move(s); } bool HasRepeatedSubstrOfWhichLengthIs(int substr_len) { vector<vector<int>> substr_hash(HASH_SIZE); int power = pow_MOD(substr_len - 1); int curH = GetHashCodeSubstr(0, substr_len); substr_hash[curH].emplace_back(0); auto curSubStr = str_.substr(0, substr_len); for (int i = 1; i <= str_.size() - substr_len; ++i) { curH = GetHashCodeSubstrQuick(curH, i, substr_len, power); if (false == substr_hash[curH].empty()) { for (auto offset : substr_hash[curH]) if (strncmp(&str_[offset], &str_[i], substr_len - 1) == 0) return true; } substr_hash[curH].emplace_back(i); } return false; } private: int GetHashCodeSubstr(int start_idx, int M) { long long hash = 0; long long rabin_fingerprint_x = 1; for (int i = start_idx + M - 1; i >= start_idx; --i) { hash += str_[i] * rabin_fingerprint_x; hash = MOD(hash); rabin_fingerprint_x = MOD(rabin_fingerprint_x * RABIN_FINGERPRINT_X); } return MOD(hash); } int GetHashCodeSubstrQuick(int prev_hash, int start_idx, int M, long long power) { return MOD(2 * (prev_hash - str_[start_idx - 1] * power) + str_[start_idx + M - 1]); } static int pow_MOD(int pow) { int power = 1; for (int i = 0; i < pow ; i++) power = MOD(power * RABIN_FINGERPRINT_X); return power; } static int MOD(const long long num) { if (num >= 0) { return num % HASH_SIZE; } else { return ((-num / HASH_SIZE + 1)*HASH_SIZE + num) % HASH_SIZE; } } private: static const int HASH_SIZE = 100003; static const int RABIN_FINGERPRINT_X = 2; string str_; }; int main() { int len; string str; cin >> len >> str; RabinKarpString S(std::move(str)); int left = 0, right = len; while (left + 1 < right) { const int mid = (left + right) / 2; if (S.HasRepeatedSubstrOfWhichLengthIs(mid)) left = mid; else right = mid; } cout << left << endl; return 0; }
- 백준 1102 - 발전소 (비트, DP)
더보기
#include<iostream> #include<vector> #include <string> #include <queue> using namespace std; const short INF = 50*16; int main() { int N, P; cin >> N; vector<bool> isOnAtFirst(N); vector<vector<short>> costs(N, vector<short>(N)); vector<short> dp(1 << N, INF); for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j) cin >> costs[i][j]; string temp; cin >> temp; int cur_state = 0; int num_gens_on = 0; for (int i = 0; i < N; ++i) if (temp[i] == 'Y') { cur_state += 1 << i; num_gens_on++; } cin >> P; if(P==0) { cout << 0; return 0; } if (num_gens_on == 0) { cout << -1; return 0; } if(num_gens_on >= P) { cout << 0; return 0; } dp[cur_state] = 0; //bottom-up 식으로 queue<int> q; queue<int> next_q; q.emplace(cur_state); short answer = INF; while (false == q.empty()) { cur_state = q.front(); q.pop(); if (num_gens_on == P) { answer = min(dp[cur_state], answer); } else { for (int i = 0; i < N; ++i) { int target_gen = 1 << i; if ((cur_state & target_gen) == 0) { short min_cost = INF; for (int j = 0; j < N; ++j) { int gen_on = 1 << j; if ((cur_state & gen_on) > 0) { if (costs[j][i] < min_cost) min_cost = costs[j][i]; //캐시 미스 많이 발생할까? } } int new_state = cur_state + target_gen; bool can_emplace = dp[new_state] == INF; short new_cost = dp[cur_state] + min_cost; dp[new_state] = min(dp[new_state], new_cost); if(can_emplace) next_q.emplace(new_state); } } if (q.empty()) { auto temp = q; q = next_q; next_q = temp; num_gens_on++; } } } cout << answer; return 0; }
- 백준 17435 - 합성함수와 쿼리 (희소 테이블)
더보기
#include <iostream> #include <vector> using namespace std; const int MAX_EXPONENT = 19; int f(int n, int x, const vector<vector<int>>& f_exp) { int cur_exponent = MAX_EXPONENT; while(n>0) { int cur_num = 1 << cur_exponent; if(cur_num <= n) { n -= cur_num; x = f_exp[cur_exponent][x]; } --cur_exponent; } return x; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); int m; cin >> m; vector<vector<int>> f_exp(MAX_EXPONENT+1, vector<int>(m+1)); for(int m_idx = 1 ; m_idx<=m ; ++m_idx) cin >> f_exp[0][m_idx]; for(int i=1;i<=MAX_EXPONENT;++i) for (int m_idx = 1; m_idx <= m; ++m_idx) f_exp[i][m_idx] = f_exp[i-1][f_exp[i - 1][m_idx]]; int Q; cin >> Q; for(int q_cnt=0 ; q_cnt<Q ; ++q_cnt) { int n, x; cin >> n >> x; cout << f(n, x, f_exp) << "\n"; } return 0; }