1/*
2 * ๋ถํ ์ ๋ณต (Divide and Conquer)
3 * Merge Sort, Quick Sort, Binary Search, Power
4 *
5 * ๋ฌธ์ ๋ฅผ ์์ ๋ถ๋ถ์ผ๋ก ๋๋์ด ํด๊ฒฐํฉ๋๋ค.
6 */
7
8#include <iostream>
9#include <vector>
10#include <algorithm>
11#include <cmath>
12#include <climits>
13
14using namespace std;
15
16// =============================================================================
17// 1. ๋น ๋ฅธ ๊ฑฐ๋ญ์ ๊ณฑ
18// =============================================================================
19
20long long power(long long base, long long exp, long long mod = LLONG_MAX) {
21 long long result = 1;
22 base %= mod;
23
24 while (exp > 0) {
25 if (exp & 1) {
26 result = (result * base) % mod;
27 }
28 base = (base * base) % mod;
29 exp >>= 1;
30 }
31
32 return result;
33}
34
35// =============================================================================
36// 2. ํ๋ ฌ ๊ฑฐ๋ญ์ ๊ณฑ
37// =============================================================================
38
39using Matrix = vector<vector<long long>>;
40
41Matrix matrixMultiply(const Matrix& A, const Matrix& B, long long mod) {
42 int n = A.size();
43 Matrix C(n, vector<long long>(n, 0));
44
45 for (int i = 0; i < n; i++) {
46 for (int j = 0; j < n; j++) {
47 for (int k = 0; k < n; k++) {
48 C[i][j] = (C[i][j] + A[i][k] * B[k][j]) % mod;
49 }
50 }
51 }
52
53 return C;
54}
55
56Matrix matrixPower(Matrix A, long long exp, long long mod) {
57 int n = A.size();
58 Matrix result(n, vector<long long>(n, 0));
59
60 // ๋จ์ ํ๋ ฌ
61 for (int i = 0; i < n; i++) result[i][i] = 1;
62
63 while (exp > 0) {
64 if (exp & 1) {
65 result = matrixMultiply(result, A, mod);
66 }
67 A = matrixMultiply(A, A, mod);
68 exp >>= 1;
69 }
70
71 return result;
72}
73
74// ํผ๋ณด๋์น (ํ๋ ฌ ๊ฑฐ๋ญ์ ๊ณฑ)
75long long fibonacciMatrix(long long n, long long mod = 1e9 + 7) {
76 if (n <= 1) return n;
77
78 Matrix M = {{1, 1}, {1, 0}};
79 Matrix result = matrixPower(M, n - 1, mod);
80 return result[0][0];
81}
82
83// =============================================================================
84// 3. ๊ฐ์ฅ ๊ฐ๊น์ด ์ ์ (Closest Pair)
85// =============================================================================
86
87struct Point {
88 double x, y;
89};
90
91double dist(const Point& p1, const Point& p2) {
92 return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
93}
94
95double bruteForce(vector<Point>& points, int left, int right) {
96 double minDist = DBL_MAX;
97 for (int i = left; i < right; i++) {
98 for (int j = i + 1; j <= right; j++) {
99 minDist = min(minDist, dist(points[i], points[j]));
100 }
101 }
102 return minDist;
103}
104
105double stripClosest(vector<Point>& strip, double d) {
106 double minDist = d;
107 sort(strip.begin(), strip.end(), [](const Point& a, const Point& b) {
108 return a.y < b.y;
109 });
110
111 for (size_t i = 0; i < strip.size(); i++) {
112 for (size_t j = i + 1; j < strip.size() && (strip[j].y - strip[i].y) < minDist; j++) {
113 minDist = min(minDist, dist(strip[i], strip[j]));
114 }
115 }
116
117 return minDist;
118}
119
120double closestPairHelper(vector<Point>& points, int left, int right) {
121 if (right - left <= 3) {
122 return bruteForce(points, left, right);
123 }
124
125 int mid = (left + right) / 2;
126 Point midPoint = points[mid];
127
128 double dl = closestPairHelper(points, left, mid);
129 double dr = closestPairHelper(points, mid + 1, right);
130 double d = min(dl, dr);
131
132 vector<Point> strip;
133 for (int i = left; i <= right; i++) {
134 if (abs(points[i].x - midPoint.x) < d) {
135 strip.push_back(points[i]);
136 }
137 }
138
139 return min(d, stripClosest(strip, d));
140}
141
142double closestPair(vector<Point>& points) {
143 sort(points.begin(), points.end(), [](const Point& a, const Point& b) {
144 return a.x < b.x;
145 });
146 return closestPairHelper(points, 0, points.size() - 1);
147}
148
149// =============================================================================
150// 4. ์ญ์ ์ ๊ฐ์ (Inversion Count)
151// =============================================================================
152
153long long mergeAndCount(vector<int>& arr, int left, int mid, int right) {
154 vector<int> L(arr.begin() + left, arr.begin() + mid + 1);
155 vector<int> R(arr.begin() + mid + 1, arr.begin() + right + 1);
156
157 size_t i = 0, j = 0;
158 int k = left;
159 long long inversions = 0;
160
161 while (i < L.size() && j < R.size()) {
162 if (L[i] <= R[j]) {
163 arr[k++] = L[i++];
164 } else {
165 arr[k++] = R[j++];
166 inversions += (L.size() - i); // ์ญ์ ์
167 }
168 }
169
170 while (i < L.size()) arr[k++] = L[i++];
171 while (j < R.size()) arr[k++] = R[j++];
172
173 return inversions;
174}
175
176long long countInversions(vector<int>& arr, int left, int right) {
177 long long inversions = 0;
178 if (left < right) {
179 int mid = (left + right) / 2;
180 inversions += countInversions(arr, left, mid);
181 inversions += countInversions(arr, mid + 1, right);
182 inversions += mergeAndCount(arr, left, mid, right);
183 }
184 return inversions;
185}
186
187// =============================================================================
188// 5. ์นด๋ผ์ธ ๋ฐ ๊ณฑ์
(Karatsuba Multiplication)
189// =============================================================================
190
191string addStrings(const string& a, const string& b) {
192 string result;
193 int carry = 0;
194 int i = a.size() - 1, j = b.size() - 1;
195
196 while (i >= 0 || j >= 0 || carry) {
197 int sum = carry;
198 if (i >= 0) sum += a[i--] - '0';
199 if (j >= 0) sum += b[j--] - '0';
200 result = char(sum % 10 + '0') + result;
201 carry = sum / 10;
202 }
203
204 return result.empty() ? "0" : result;
205}
206
207// =============================================================================
208// 6. ์ต๋ ๋ถ๋ถ ๋ฐฐ์ด ํฉ (๋ถํ ์ ๋ณต)
209// =============================================================================
210
211int maxCrossingSum(const vector<int>& arr, int left, int mid, int right) {
212 int leftSum = INT_MIN;
213 int sum = 0;
214 for (int i = mid; i >= left; i--) {
215 sum += arr[i];
216 leftSum = max(leftSum, sum);
217 }
218
219 int rightSum = INT_MIN;
220 sum = 0;
221 for (int i = mid + 1; i <= right; i++) {
222 sum += arr[i];
223 rightSum = max(rightSum, sum);
224 }
225
226 return leftSum + rightSum;
227}
228
229int maxSubArrayDC(const vector<int>& arr, int left, int right) {
230 if (left == right) return arr[left];
231
232 int mid = (left + right) / 2;
233 return max({
234 maxSubArrayDC(arr, left, mid),
235 maxSubArrayDC(arr, mid + 1, right),
236 maxCrossingSum(arr, left, mid, right)
237 });
238}
239
240// =============================================================================
241// ํ
์คํธ
242// =============================================================================
243
244int main() {
245 cout << "============================================================" << endl;
246 cout << "๋ถํ ์ ๋ณต ์์ " << endl;
247 cout << "============================================================" << endl;
248
249 // 1. ๋น ๋ฅธ ๊ฑฐ๋ญ์ ๊ณฑ
250 cout << "\n[1] ๋น ๋ฅธ ๊ฑฐ๋ญ์ ๊ณฑ" << endl;
251 cout << " 2^10 = " << power(2, 10) << endl;
252 cout << " 3^20 mod 1000 = " << power(3, 20, 1000) << endl;
253
254 // 2. ํผ๋ณด๋์น (ํ๋ ฌ ๊ฑฐ๋ญ์ ๊ณฑ)
255 cout << "\n[2] ํผ๋ณด๋์น (ํ๋ ฌ ๊ฑฐ๋ญ์ ๊ณฑ)" << endl;
256 cout << " F(10) = " << fibonacciMatrix(10) << endl;
257 cout << " F(50) mod 10^9+7 = " << fibonacciMatrix(50) << endl;
258
259 // 3. ๊ฐ์ฅ ๊ฐ๊น์ด ์ ์
260 cout << "\n[3] ๊ฐ์ฅ ๊ฐ๊น์ด ์ ์" << endl;
261 vector<Point> points = {{2, 3}, {12, 30}, {40, 50}, {5, 1}, {12, 10}, {3, 4}};
262 cout << " ์ 6๊ฐ" << endl;
263 cout << " ์ต์ ๊ฑฐ๋ฆฌ: " << closestPair(points) << endl;
264
265 // 4. ์ญ์ ์ ๊ฐ์
266 cout << "\n[4] ์ญ์ ์ ๊ฐ์" << endl;
267 vector<int> inv = {8, 4, 2, 1};
268 cout << " ๋ฐฐ์ด: [8, 4, 2, 1]" << endl;
269 cout << " ์ญ์ ์: " << countInversions(inv, 0, inv.size() - 1) << endl;
270
271 // 5. ์ต๋ ๋ถ๋ถ ๋ฐฐ์ด ํฉ
272 cout << "\n[5] ์ต๋ ๋ถ๋ถ ๋ฐฐ์ด ํฉ (๋ถํ ์ ๋ณต)" << endl;
273 vector<int> arr = {-2, 1, -3, 4, -1, 2, 1, -5, 4};
274 cout << " ๋ฐฐ์ด: [-2,1,-3,4,-1,2,1,-5,4]" << endl;
275 cout << " ์ต๋ ํฉ: " << maxSubArrayDC(arr, 0, arr.size() - 1) << endl;
276
277 // 6. ๋ณต์ก๋ ์์ฝ
278 cout << "\n[6] ๋ณต์ก๋ ์์ฝ" << endl;
279 cout << " | ์๊ณ ๋ฆฌ์ฆ | ์๊ฐ๋ณต์ก๋ |" << endl;
280 cout << " |--------------------|----------------|" << endl;
281 cout << " | ๋น ๋ฅธ ๊ฑฐ๋ญ์ ๊ณฑ | O(log n) |" << endl;
282 cout << " | ํ๋ ฌ ๊ฑฐ๋ญ์ ๊ณฑ | O(kยณ log n) |" << endl;
283 cout << " | ๊ฐ์ฅ ๊ฐ๊น์ด ์ ์ | O(n log n) |" << endl;
284 cout << " | ์ญ์ ์ ๊ฐ์ | O(n log n) |" << endl;
285 cout << " | ๋ณํฉ/ํต ์ ๋ ฌ | O(n log n) |" << endl;
286
287 cout << "\n============================================================" << endl;
288
289 return 0;
290}