<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>복습 정리 노트</title>
    <link>https://restudycafe.tistory.com/</link>
    <description>공부 기록 저장용</description>
    <language>ko</language>
    <pubDate>Wed, 8 Apr 2026 19:39:41 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>restudy</managingEditor>
    <item>
      <title>[광고][노트북 추천] MSI 2025 스텔스 18 코어Ultra9 지포스 RTX 5070 Ti</title>
      <link>https://restudycafe.tistory.com/662</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;* 이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오랜만에&amp;nbsp;노트북을&amp;nbsp;교체할&amp;nbsp;목적으로&amp;nbsp;여러&amp;nbsp;제품을&amp;nbsp;살펴보던&amp;nbsp;중,&amp;nbsp;해당&amp;nbsp;모델을&amp;nbsp;확인하게&amp;nbsp;되어&amp;nbsp;주요&amp;nbsp;사양을&amp;nbsp;정리합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;MSI 2025 스텔스 18 코어Ultra9 지포스 RTX 5070 Ti&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://link.coupang.com/a/c599QY&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://link.coupang.com/a/c599QY&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1763625101390&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;MSI 2025 스텔스 18 코어Ultra9 지포스 RTX 5070 Ti - 노트북 | 쿠팡&quot; data-og-description=&quot;쿠팡에서 MSI 2025 스텔스 18 코어Ultra9 지포스 RTX 5070 Ti 구매하고 더 많은 혜택을 받으세요! 지금 할인중인 다른 노트북 제품도 바로 쿠팡에서 확인할 수 있습니다.&quot; data-og-host=&quot;www.coupang.com&quot; data-og-source-url=&quot;https://link.coupang.com/a/c599QY&quot; data-og-url=&quot;https://www.coupang.com/vp/products/8792004318&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/pUVhe/hyZOfoO8AL/qekKVVDKsMZ328RkelM010/img.jpg?width=492&amp;amp;height=492&amp;amp;face=0_0_492_492,https://scrap.kakaocdn.net/dn/bUKXqz/hyZNx4EJdv/R01cSOlIPN3wM8CWjkje71/img.jpg?width=492&amp;amp;height=492&amp;amp;face=0_0_492_492&quot;&gt;&lt;a href=&quot;https://link.coupang.com/a/c599QY&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://link.coupang.com/a/c599QY&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/pUVhe/hyZOfoO8AL/qekKVVDKsMZ328RkelM010/img.jpg?width=492&amp;amp;height=492&amp;amp;face=0_0_492_492,https://scrap.kakaocdn.net/dn/bUKXqz/hyZNx4EJdv/R01cSOlIPN3wM8CWjkje71/img.jpg?width=492&amp;amp;height=492&amp;amp;face=0_0_492_492');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;MSI 2025 스텔스 18 코어Ultra9 지포스 RTX 5070 Ti - 노트북 | 쿠팡&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;쿠팡에서 MSI 2025 스텔스 18 코어Ultra9 지포스 RTX 5070 Ti 구매하고 더 많은 혜택을 받으세요! 지금 할인중인 다른 노트북 제품도 바로 쿠팡에서 확인할 수 있습니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.coupang.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이&amp;nbsp;제품은&amp;nbsp;Intel&amp;nbsp;Core&amp;nbsp;Ultra&amp;nbsp;9&amp;nbsp;275HX&amp;nbsp;프로세서와&amp;nbsp;NVIDIA&amp;nbsp;GeForce&amp;nbsp;RTX&amp;nbsp;5070&amp;nbsp;Ti&amp;nbsp;Laptop&amp;nbsp;GPU(140W&amp;nbsp;다이나믹&amp;nbsp;부스트)를&amp;nbsp;탑재하고&amp;nbsp;있고,&amp;nbsp;일반적인&amp;nbsp;사무&amp;nbsp;작업,&amp;nbsp;개발,&amp;nbsp;영상&amp;nbsp;편집&amp;nbsp;등&amp;nbsp;다양한&amp;nbsp;용도의&amp;nbsp;고성능&amp;nbsp;작업&amp;nbsp;환경을&amp;nbsp;구성하는&amp;nbsp;데&amp;nbsp;적합한&amp;nbsp;사양이라고&amp;nbsp;생각됩니다. &lt;br /&gt;&lt;br /&gt;디스플레이는&amp;nbsp;18형&amp;nbsp;QHD&amp;nbsp;플러스&amp;nbsp;해상도(2560&amp;times;1600),&amp;nbsp;16대10&amp;nbsp;비율,&amp;nbsp;240Hz&amp;nbsp;주사율,&amp;nbsp;DCI-P3&amp;nbsp;100퍼센트&amp;nbsp;색역,&amp;nbsp;500니트&amp;nbsp;밝기로&amp;nbsp;구성되어&amp;nbsp;있으며,&amp;nbsp;대형&amp;nbsp;화면&amp;nbsp;기반의&amp;nbsp;작업&amp;nbsp;환경을&amp;nbsp;필요로&amp;nbsp;하는&amp;nbsp;경우에&amp;nbsp;활용성이&amp;nbsp;높다고&amp;nbsp;생각됩니다. &lt;br /&gt;&lt;br /&gt;메모리는&amp;nbsp;DDR5&amp;nbsp;32GB(2슬롯,&amp;nbsp;최대&amp;nbsp;96GB&amp;nbsp;확장&amp;nbsp;가능),&amp;nbsp;저장장치는&amp;nbsp;1TB&amp;nbsp;NVMe&amp;nbsp;M.2&amp;nbsp;SSD로&amp;nbsp;구성되어&amp;nbsp;있어&amp;nbsp;일반적인&amp;nbsp;개발&amp;nbsp;작업이나&amp;nbsp;대용량&amp;nbsp;데이터&amp;nbsp;처리&amp;nbsp;용도로&amp;nbsp;사용하는&amp;nbsp;데&amp;nbsp;무리가&amp;nbsp;없어보입니다. &lt;br /&gt;&lt;br /&gt;네트워크는&amp;nbsp;Wi-Fi&amp;nbsp;7,&amp;nbsp;Bluetooth&amp;nbsp;5.4를&amp;nbsp;지원합니다.&amp;nbsp;입출력&amp;nbsp;구성은&amp;nbsp;Thunderbolt&amp;nbsp;4,&amp;nbsp;USB&amp;nbsp;Type-A,&amp;nbsp;USB&amp;nbsp;Type-C,&amp;nbsp;HDMI&amp;nbsp;2.1,&amp;nbsp;SD&amp;nbsp;카드&amp;nbsp;리더,&amp;nbsp;RJ45&amp;nbsp;유선&amp;nbsp;LAN&amp;nbsp;등&amp;nbsp;여러&amp;nbsp;단자가&amp;nbsp;포함되어&amp;nbsp;있네요. &lt;br /&gt;&lt;br /&gt;배터리&amp;nbsp;용량은&amp;nbsp;99.9Wh이며,&amp;nbsp;무게는&amp;nbsp;당연히&amp;nbsp;꽤&amp;nbsp;많이&amp;nbsp;나가지만,&amp;nbsp;대형&amp;nbsp;고성능&amp;nbsp;노트북&amp;nbsp;기준에서는&amp;nbsp;이동성을&amp;nbsp;어느&amp;nbsp;정도&amp;nbsp;확보한&amp;nbsp;편&amp;nbsp;같습니다. &lt;br /&gt;&lt;br /&gt;전체적으로 고성능 CPU와 GPU 구성, 화면 사양, 확장성, 포트 구성 등 핵심 요소를 기준으로 판단했을 때 균형 잡힌 사양의 제품인 것 같네요!&lt;/p&gt;</description>
      <category>기타</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/662</guid>
      <comments>https://restudycafe.tistory.com/662#entry662comment</comments>
      <pubDate>Thu, 20 Nov 2025 16:57:04 +0900</pubDate>
    </item>
    <item>
      <title>머신러닝이 약학에 어떻게 적용될 수 있을까?</title>
      <link>https://restudycafe.tistory.com/661</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;머신러닝이 약학에 어떻게 적용될 수 있을지 간단히 정리해 보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;약동학 = pharmacokinetic&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 약물이 체내에서 어떻게 &lt;span style=&quot;color: #ee2323;&quot;&gt;ADME&lt;/span&gt;(흡수, 분포, 대사, 배설) 되는지 연구&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 약물의 체내 행동을 &lt;u&gt;시간에 따라&lt;/u&gt; 분석하고, 약물의 &lt;u&gt;농도-시간 곡선&lt;/u&gt;을 평가하여 &lt;span style=&quot;color: #ee2323;&quot;&gt;약물의 효과를 예측&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;ECMO (체외막산소요법, &lt;span style=&quot;text-align: left;&quot;&gt;Extracorporeal Membrane Oxygenation)&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;text-align: left;&quot;&gt;- (회복 가능성이 있는 심부전 환자에 대해)&lt;span style=&quot;text-align: left;&quot;&gt; 정맥혈을 뽑아내어 &lt;span style=&quot;color: #ee2323;&quot;&gt;혈액에 산소를 공급&lt;/span&gt;하고 환자의 순환 및 호흡 기능을 보조하는 장치&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 사용 시 병용되는 약물: &lt;u&gt;항응고제, 항생제, 진정제 및 진통제, 이뇨제, 심혈관계 약물&lt;/u&gt; 등&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;머신러닝(ML)과 딥러닝(DL)의 활용&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;환자의 연령, 체중, 신장 기능, 간 기능, 병력 등 &lt;u&gt;약물 투여에 중요한 변수에 따른&lt;/u&gt; &lt;span style=&quot;color: #ee2323;&quot;&gt;최적의 약물 투여량&lt;/span&gt;을 ML/DL로 결정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, 여기에 어떤 &lt;u&gt;머신러닝 모델을 선택할지&lt;/u&gt;는&lt;b&gt; 문제의 특성&lt;/b&gt;과 &lt;b&gt;데이터의 특성&lt;/b&gt;에 따라 달라진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;머신러닝(ML) 모델의 종류&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 선형 회귀: 비선형 관계를 잘 처리하지 못함 (당연히 최적의 약물 농도 구할 때에는 쓸 수 없음)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 랜덤 포레스트: 여러 개의 트리가 각각의 추론을 수행하고, 여러 트리들의 추론 결과를 종합하여 최종 결정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 큰 데이터셋에서 훈련 시간 오래 걸린다고 함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Scikit-learn과 Tensorflow&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;Scikit-learn&lt;/span&gt;: 머신러닝에 자주 사용되는 라이브러리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;Tensorflow&lt;/span&gt;: 딥러닝에 자주 사용되는 라이브러리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 훈련 데이터로 선형 회귀를 학습시키고, 랜덤으로 생성한 테스트 데이터를 가지고 MSE를 측정해서 얼마나 학습이 잘 되었는지 확인하는 예제 코드이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;Scikit-learn&lt;/b&gt; 라이브러리의 &lt;b&gt;머신러닝&lt;/b&gt;을 이용한 예제&lt;/p&gt;
&lt;pre id=&quot;code_1721228676119&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error

X = np.array([[1], [2], [3], [4], [5]])
y = np.array([1, 3, 3, 2, 5])

# 훈련 데이터와 테스트 데이터로 분리
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 모델 초기화 및 훈련
model = LinearRegression()
model.fit(X_train, y_train)

# 예측 및 성능 평가
y_pred = model.predict(X_test)
mse = mean_squared_error(y_test, y_pred)

print(&quot;Mean Squared Error:&quot;, mse)
print(&quot;Predictions:&quot;, y_pred)&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1721228694999&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Mean Squared Error: 1.6530612244897955
Predictions: [1.71428571]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;Tensorflow&lt;/b&gt; 라이브러리의 &lt;b&gt;딥러닝&lt;/b&gt;을 이용한 예제&lt;/p&gt;
&lt;pre id=&quot;code_1721228766891&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import numpy as np
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.optimizers import Adam
from sklearn.model_selection import train_test_split

X = np.array([[1], [2], [3], [4], [5]])
y = np.array([1, 3, 3, 2, 5])

# 훈련 데이터와 테스트 데이터로 분리
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 모델 정의
model = Sequential()
model.add(Dense(10, input_dim=1, activation='relu'))
model.add(Dense(1))

# 모델 컴파일
model.compile(optimizer=Adam(learning_rate=0.01), loss='mean_squared_error')

# 모델 훈련
model.fit(X_train, y_train, epochs=100, verbose=0)

# 예측 및 성능 평가
y_pred = model.predict(X_test)
mse = np.mean((y_test - y_pred.flatten())**2)

print(&quot;Mean Squared Error:&quot;, mse)
print(&quot;Predictions:&quot;, y_pred.flatten())&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1721228776155&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Mean Squared Error: 1.2140690288737375
Predictions: [1.898152]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;최적의 약물 투여량을 ML/DL로 구하는 방법&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 먼저 다음과 같은 데이터를 수집합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 환자 데이터: &lt;span style=&quot;color: #ee2323;&quot;&gt;나이, 성별, 체중, 키&lt;/span&gt;, 병력 등 환자의 기본 정보&lt;br /&gt;&amp;nbsp; - 약물 데이터: 약물 &lt;span style=&quot;color: #ee2323;&quot;&gt;종류, 투여량, 투여 빈도&lt;/span&gt; 등&lt;br /&gt;&amp;nbsp; - 생체 지표: &lt;span style=&quot;color: #ee2323;&quot;&gt;혈압, 혈당 수치, 심박수&lt;/span&gt; 등 &lt;u&gt;약물 투여 후 측정된 생체 지표&lt;/u&gt;&lt;br /&gt;&amp;nbsp; - 치료 결과: 치료의 효과와 부작용 여부 등&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;span style=&quot;color: #ee2323;&quot;&gt;딥러닝 모델(ANN, LSTM)을 이용하여 약물 투여와 결과 사이의 관계를 학습시켜 모델링&lt;/span&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; (- 간단한 경우, 위에서 소개한 간단한 머신러닝 모델(선형 회귀, 랜덤 포레스트 등)을 활용할 수도 있음)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; (- 약물 투여량에 따른 생체 지표는 당연히 비선형으로 나오는 것이 상식적)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 딥러닝은 머신러닝에 비해 큰 규모의 학습 데이터가 필요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - &lt;b&gt;하이퍼파라미터 튜닝&lt;/b&gt; 과정을 통해 최적의 성능을 내기 위한 하이퍼파라미터를 찾습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;다층 퍼셉트론(MLP)&lt;/b&gt;을 가진 &lt;b&gt;인공 신경망(ANN)&lt;/b&gt;을 사용해 &lt;span style=&quot;color: #ee2323;&quot;&gt;최적의 약물 투여량을 찾는 예제 코드&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- X: 환자의 다양한 특징을 나타내는 수치형 데이터 (여기서는 각각이 10개의 특징을 가진 데이터셋, 이것이 실제로는 환자의 나이, 성별, 체중, 키 등의 변수일 수 있음) &lt;br /&gt;- Y: 각 환자에 대한 최적의 약물 투여량 &lt;br /&gt;- 결과적으로 얻어지는 것:&lt;span style=&quot;color: #ee2323;&quot;&gt; '비선형'의 회귀 모델&lt;/span&gt;. 이 비선형의 회귀 모델을 통해 &lt;span style=&quot;color: #ee2323;&quot;&gt;임의의 입력 데이터(= 환자 데이터)에 대해 최적의 약물 투여량을 예측할 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1721229862058&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import numpy as np
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from sklearn.model_selection import train_test_split

# 가상의 예제 데이터 생성
# 실제로는 환자 데이터, 약물 데이터, 생체 지표 등으로 이루어진 데이터셋 사용
X = np.random.rand(1000, 10)  # 1000명의 환자, 10개의 특징
y = np.random.rand(1000)  # 1000명의 환자에 대한 약물 투여량

# 데이터를 훈련 데이터와 테스트 데이터로 분리
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 신경망 모델 정의
model = Sequential()
model.add(Dense(64, input_dim=X_train.shape[1], activation='relu'))
model.add(Dense(32, activation='relu'))
model.add(Dense(1))  # 약물 투여량을 예측하는 하나의 출력 뉴런

model.compile(optimizer='adam', loss='mean_squared_error')

# 모델 훈련 과정
model.fit(X_train, y_train, epochs=100, batch_size=32, verbose=1, validation_split=0.2)

# 모델을 평가
mse = model.evaluate(X_test, y_test)
print(&quot;Mean Squared Error:&quot;, mse)

# 새로운 데이터 예측
new_data = np.random.rand(1, 10)  # 가상의 새로운 환자 데이터
predicted_dosage = model.predict(new_data)
print(&quot;Predicted Dosage:&quot;, predicted_dosage)&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1721229936148&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Epoch 1/100
20/20 [==============================] - 1s 9ms/step - loss: 0.2945 - val_loss: 0.1110
Epoch 2/100
20/20 [==============================] - 0s 3ms/step - loss: 0.1119 - val_loss: 0.1002
Epoch 3/100
20/20 [==============================] - 0s 3ms/step - loss: 0.0952 - val_loss: 0.0989

...

Epoch 98/100
20/20 [==============================] - 0s 3ms/step - loss: 0.0414 - val_loss: 0.1202
Epoch 100/100
20/20 [==============================] - 0s 3ms/step - loss: 0.0411 - val_loss: 0.1229
7/7 [==============================] - 0s 1ms/step - loss: 0.1183
Mean Squared Error: 0.1182592362165451
Predicted Dosage: [[0.3699172]]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;코드 원문 링크&lt;/h4&gt;
&lt;figure id=&quot;og_1721230434676&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - yeohj0710/ml-dl-simple-sample&quot; data-og-description=&quot;Contribute to yeohj0710/ml-dl-simple-sample development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/yeohj0710/ml-dl-simple-sample&quot; data-og-url=&quot;https://github.com/yeohj0710/ml-dl-simple-sample&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bViR9K/hyWCFKEPum/1icXikmSuY1UBL6Hk5eKt1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/yeohj0710/ml-dl-simple-sample&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/yeohj0710/ml-dl-simple-sample&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bViR9K/hyWCFKEPum/1icXikmSuY1UBL6Hk5eKt1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - yeohj0710/ml-dl-simple-sample&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Contribute to yeohj0710/ml-dl-simple-sample development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>기타</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/661</guid>
      <comments>https://restudycafe.tistory.com/661#entry661comment</comments>
      <pubDate>Wed, 17 Jul 2024 21:24:56 +0900</pubDate>
    </item>
    <item>
      <title>NextJS 당근마켓 클론코딩: #5.0 ~ #12.7 필기 내용 정리</title>
      <link>https://restudycafe.tistory.com/660</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이 포스트에서는 당근마켓 클론코딩의 #5.0 ~ #12.7 단원에서 학습한 내용들을 정리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;# 5.0 Route Handlers&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그인 form을 입력하면 백엔드에서 값을 어떻게 가져가서 확인하고, 로그인을 시켜주는가 &lt;br /&gt;&lt;br /&gt;&amp;lt;기존&amp;nbsp;방식&amp;gt; &lt;br /&gt;API route를 만들고, API URL을 이용해서 데이터를 전송&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 이때 route handler를 만들기 위해서는 파일명을 반드시 route.ts로 해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 그래야 NextJS에서 route handler임을 인식한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프론트엔드에서 fetch(주소, { method: &quot;POST&quot;, body: JSON.stringify({ value: 값 }))로 전송하면, 백엔드에서 request: NextRequest에 대해 await request.json()과 같이 값을 받을 수 있었다. &lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;# 5.1 Server Actions&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;새로운 방식&amp;gt; &lt;br /&gt;NextJS의 Server Actions를 이용하면 프론트엔드에서 전달한 값을 백엔드에서 받는 과정을 훨씬 간단하게 구현할 수 있다. &lt;br /&gt;함수&amp;nbsp;내에&amp;nbsp;&quot;use&amp;nbsp;server&quot;;를&amp;nbsp;작성하면,&amp;nbsp;이&amp;nbsp;함수는&amp;nbsp;서버에서만&amp;nbsp;실행되도록&amp;nbsp;해&amp;nbsp;준다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(이때&amp;nbsp;함수는&amp;nbsp;비동기&amp;nbsp;함수이므로&amp;nbsp;async&amp;nbsp;함수로&amp;nbsp;선언해&amp;nbsp;주어야&amp;nbsp;한다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;함수를&amp;nbsp;선언하고&amp;nbsp;&quot;use&amp;nbsp;server&quot;;를&amp;nbsp;입력해&amp;nbsp;준&amp;nbsp;다음,&amp;nbsp;이&amp;nbsp;함수&amp;nbsp;이름을&amp;nbsp;form의&amp;nbsp;props에서&amp;nbsp;action={함수명}과&amp;nbsp;같이&amp;nbsp;작성해&amp;nbsp;주면&amp;nbsp;끝이다. &lt;br /&gt;이제&amp;nbsp;프론트엔드에서&amp;nbsp;form을&amp;nbsp;입력하고&amp;nbsp;제출하면,&amp;nbsp;해당&amp;nbsp;함수가&amp;nbsp;백엔드에서&amp;nbsp;실행된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(이때&amp;nbsp;Server&amp;nbsp;Action을&amp;nbsp;이용해&amp;nbsp;데이터가&amp;nbsp;전송된다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;함수에서&amp;nbsp;데이터를&amp;nbsp;받기&amp;nbsp;위해서는,&amp;nbsp;매개변수를&amp;nbsp;'FormData'&amp;nbsp;타입으로&amp;nbsp;선언한&amp;nbsp;다음,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'변수명.get(&quot;form의&amp;nbsp;name&quot;)'과&amp;nbsp;적어주면&amp;nbsp;된다. &lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;# 5.2 useFormStatus&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;useFormStatus&amp;nbsp;hook&lt;/span&gt;을&amp;nbsp;사용하면,&amp;nbsp;컴포넌트가&amp;nbsp;로딩&amp;nbsp;중인&amp;nbsp;상황도&amp;nbsp;쉽게&amp;nbsp;컨트롤할&amp;nbsp;수&amp;nbsp;있다. &lt;br /&gt;const&amp;nbsp;{&amp;nbsp;pending&amp;nbsp;}&amp;nbsp;=&amp;nbsp;useFormStatus();와&amp;nbsp;같이&amp;nbsp;선언한&amp;nbsp;다음,&amp;nbsp;&amp;lt;button&amp;nbsp;disabled={pending}&amp;nbsp;/&amp;gt;과&amp;nbsp;같이&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(Component&amp;nbsp;코드&amp;nbsp;최상단에&amp;nbsp;&quot;use&amp;nbsp;client&quot;;를&amp;nbsp;선언해&amp;nbsp;주어야&amp;nbsp;한다.) &lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;# 5.3 useFormState&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;const [state, action] = useFormState(함수, 초깃값(null));&lt;/span&gt;와 같이 실행한다. &lt;br /&gt;state는&amp;nbsp;action의&amp;nbsp;return&amp;nbsp;값이고,&amp;nbsp;action은&amp;nbsp;함수를&amp;nbsp;실행한다. &lt;br /&gt;이때&amp;nbsp;action은&amp;nbsp;(action의)&amp;nbsp;이전&amp;nbsp;state와&amp;nbsp;함께&amp;nbsp;호출된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;action을&amp;nbsp;useFormState를&amp;nbsp;이용해서&amp;nbsp;넘겨주면,&amp;nbsp;&lt;u&gt;action의&amp;nbsp;결과&lt;/u&gt;를&amp;nbsp;반환한다. &lt;br /&gt;&amp;rarr;&amp;nbsp;useFormState가&amp;nbsp;action을&amp;nbsp;호출하면,&amp;nbsp;action은&amp;nbsp;formData와&amp;nbsp;함께&amp;nbsp;이전에&amp;nbsp;반환한&amp;nbsp;state(없으면&amp;nbsp;초깃값)와&amp;nbsp;함께&amp;nbsp;실행된다. &lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;# 6.5 Recap&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Zod&lt;/b&gt;: 데이터에 대한 schema를 정의하여 올바르지 않은 데이터가 백엔드로 전달되는 것을 방지해 준다. &lt;br /&gt;하지만&amp;nbsp;Zod를&amp;nbsp;사용하더라도,&amp;nbsp;form&amp;nbsp;자체에서&amp;nbsp;validation을&amp;nbsp;이중으로&amp;nbsp;처리해&amp;nbsp;줄&amp;nbsp;필요는&amp;nbsp;있다. &lt;br /&gt;&lt;br /&gt;formSchema의&amp;nbsp;&lt;u&gt;safeParse()&lt;/u&gt;&amp;nbsp;메서드:&amp;nbsp;데이터를&amp;nbsp;파싱할&amp;nbsp;때&amp;nbsp;에러가&amp;nbsp;발생하더라도&amp;nbsp;에러를&amp;nbsp;throw&amp;nbsp;하지&amp;nbsp;않고,&amp;nbsp;데이터와&amp;nbsp;에러를&amp;nbsp;반환한다. &lt;br /&gt;result.error.flatten()&amp;nbsp;메서드:&amp;nbsp;여러&amp;nbsp;에러를&amp;nbsp;하나의&amp;nbsp;배열에&amp;nbsp;담아서&amp;nbsp;반환해&amp;nbsp;준다.&amp;nbsp;이를&amp;nbsp;통해&amp;nbsp;에러를&amp;nbsp;더&amp;nbsp;쉽게&amp;nbsp;처리할&amp;nbsp;수&amp;nbsp;있다. &lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;# 6.7 Coerce&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Zod에서 z.coerce.number()와 같이 coerce 속성을 이용하면 유저의 입력을 자동으로 number 타입으로 변환해 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;# 7.0 Setup&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Prisma&lt;/b&gt;: 사용자와 DB 사이의 통역사 역할 &lt;br /&gt;DB&amp;nbsp;내&amp;nbsp;데이터&amp;nbsp;구조를&amp;nbsp;prisma의&amp;nbsp;언어로&amp;nbsp;알려주면,&amp;nbsp;prisma가&amp;nbsp;우리가&amp;nbsp;연결해&amp;nbsp;준&amp;nbsp;DB를&amp;nbsp;관리해&amp;nbsp;준다. &lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;# 8.3 Iron Session&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;iron-session&lt;/span&gt;: NodeJS에서 session을 처리하기 위한 middleware &lt;br /&gt;&lt;b&gt;getIronSession()&lt;/b&gt;:&amp;nbsp;session을&amp;nbsp;관리할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;함수로,&amp;nbsp;session&amp;nbsp;데이터에&amp;nbsp;접근/조작&amp;nbsp;가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;session.id = user!.id와 같이 session 값을 설정한 이후에는,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반드시 await session.save()와 같이 session을 저장해 주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;로그아웃과 같은 기능을 구현할 때는 const session = await getSession()으로 session을 얻어준 다음,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;await session.destroy()와 같이 session을 제거한다. &lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;//@ts-ignore&lt;/span&gt;:&amp;nbsp;TypeScript가&amp;nbsp;다음&amp;nbsp;줄의&amp;nbsp;에러를&amp;nbsp;무시할&amp;nbsp;수&amp;nbsp;있게&amp;nbsp;해&amp;nbsp;준다. &lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;# 8.9 Middleware&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;/app 폴더가 위치한 경로와 동일한 경로에 &lt;span style=&quot;color: #ee2323;&quot;&gt;middleware.ts&lt;/span&gt;를 생성하면, NextJS가 자동으로 이를 middleware로 인식한다. (파일 내 함수 이름 역시 middleware()이어야 한다.) &lt;br /&gt;middleware는&amp;nbsp;&lt;u&gt;페이지에&amp;nbsp;접속하기&amp;nbsp;이전에&amp;nbsp;페이지&amp;nbsp;접속&amp;nbsp;권한&amp;nbsp;검사&amp;nbsp;등&amp;nbsp;다양한&amp;nbsp;처리&lt;/u&gt;들을&amp;nbsp;수행할&amp;nbsp;수&amp;nbsp;있다. &lt;br /&gt;&lt;br /&gt;middleware가&amp;nbsp;특정&amp;nbsp;페이지에서만&amp;nbsp;작동하도록&amp;nbsp;하려면,&amp;nbsp;config라는&amp;nbsp;객체&amp;nbsp;내에&amp;nbsp;작성해주면&amp;nbsp;된다.&amp;nbsp;(역시&amp;nbsp;변수명&amp;nbsp;config로&amp;nbsp;고정&amp;nbsp;필수,&amp;nbsp;정규표현식을&amp;nbsp;사용할&amp;nbsp;수도&amp;nbsp;있고,&amp;nbsp;!&amp;nbsp;기호를&amp;nbsp;붙이면&amp;nbsp;특정&amp;nbsp;페이지에서만&amp;nbsp;middleware가&amp;nbsp;실행되지&amp;nbsp;않도록&amp;nbsp;할&amp;nbsp;수도&amp;nbsp;있음) &lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;# 8.11 Edge Runtime&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NextJS의 middleware는 &lt;u&gt;빠르게 동작&lt;/u&gt;할 수 있는 Edge runtime에서 작동하기 때문에 특정 기능은 사용하지 못한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(따라서&amp;nbsp;&lt;u&gt;session이나&amp;nbsp;cookie&amp;nbsp;확인,&amp;nbsp;그리고&amp;nbsp;redirect&amp;nbsp;정도만&amp;nbsp;사용&lt;/u&gt;하는&amp;nbsp;것이&amp;nbsp;적절) &lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;# 9.1 Github Authentication&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;OAuth&lt;/b&gt;: 사용자 인증 방식 (네이버, 카카오 등 다양한 플랫폼 모두 동일한 방식 사용) &lt;br /&gt;github의 경우 다음의 링크에서&amp;nbsp;새&amp;nbsp;OAuth를&amp;nbsp;등록할&amp;nbsp;수&amp;nbsp;있다.&lt;/p&gt;
&lt;pre id=&quot;code_1714375754079&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;https://github.com/settings/applications/new&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;# 9.7 Twilio SMS&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Twilio&lt;/b&gt;를 이용해 SMS 인증 기능을 구현한다. &lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;# 10.1 Tab Bar&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소괄호 이름 폴더로 라우트 디렉토리들을 묶을 경우 &lt;u&gt;묶인 디렉토리들에는 서로 다른 layout&lt;/u&gt;을 적용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(단순히 라우트에 영향을 받지 않도록 라우트 디렉토리들을 묶는 것만이 장점이 아님)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;# 10.6 Image Hostnames&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NextJS의 Image는 &lt;span style=&quot;color: #ee2323;&quot;&gt;이미지를 자동으로 최적화&lt;/span&gt;를 해 주어 성능을 향상시키고 빠른 로딩이 되도록 해 준다. &lt;br /&gt;하지만&amp;nbsp;외부&amp;nbsp;호스트의&amp;nbsp;이미지(다른&amp;nbsp;사이트의&amp;nbsp;이미지&amp;nbsp;링크&amp;nbsp;등)를&amp;nbsp;불러올&amp;nbsp;때는&amp;nbsp;보안&amp;nbsp;때문에&amp;nbsp;이&amp;nbsp;기능이&amp;nbsp;허용되지&amp;nbsp;않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;따라서&amp;nbsp;&lt;u&gt;next.config.mjs&lt;/u&gt;에서&amp;nbsp;hostname들을&amp;nbsp;등록해&amp;nbsp;주어야&amp;nbsp;한다. &lt;br /&gt;(nextConfig&amp;nbsp;&amp;gt;&amp;nbsp;images&amp;nbsp;&amp;gt;&amp;nbsp;remotePatterns&amp;nbsp;&amp;gt;&amp;nbsp;hostname)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;# 10.9 Infinite Scrolling&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;infinite scrolling의 구현: &lt;b&gt;IntersectionObserver&lt;/b&gt;를 이용해 페이지의 하단에 도달했는지를 감지할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;# 11.0 Introduction&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;Zod + React Hook Form + Server Actions&lt;/u&gt;를 함께 활용해 Server upload하는 방법을 배운다. &lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;NextJS&amp;nbsp;cache&lt;/span&gt;:&amp;nbsp;&lt;u&gt;DB&amp;nbsp;response를&amp;nbsp;server&amp;nbsp;memory에&amp;nbsp;저장하여&amp;nbsp;재사용&lt;/u&gt;할&amp;nbsp;수&amp;nbsp;있게&amp;nbsp;해&amp;nbsp;준다.&amp;nbsp;이를&amp;nbsp;통해&amp;nbsp;DB에&amp;nbsp;매번&amp;nbsp;접속&amp;nbsp;및&amp;nbsp;로딩하지&amp;nbsp;않고&amp;nbsp;데이터를&amp;nbsp;즉시&amp;nbsp;볼&amp;nbsp;수&amp;nbsp;있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;# 11.3 Images Setup&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Cloudflare images&lt;/b&gt;&lt;/span&gt;: 이미지 저장 및 로드, 최적화에 특화된 서비스 &lt;br /&gt;user가&amp;nbsp;server에&amp;nbsp;요청을&amp;nbsp;보내면,&amp;nbsp;user&amp;nbsp;&amp;rarr;&amp;nbsp;server&amp;nbsp;&amp;rarr;&amp;nbsp;cloudflare&amp;nbsp;순서로&amp;nbsp;파일이&amp;nbsp;전송되는&amp;nbsp;것이&amp;nbsp;아닌,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;user&amp;nbsp;&amp;rarr;&amp;nbsp;cloudflare&lt;/span&gt;&amp;nbsp;순서로&amp;nbsp;효율적으로&amp;nbsp;이미지&amp;nbsp;업로드가&amp;nbsp;진행된다. &lt;br /&gt;cloudflare는&amp;nbsp;저장된&amp;nbsp;image의&amp;nbsp;URL을&amp;nbsp;반환하며,&amp;nbsp;이&amp;nbsp;URL만&amp;nbsp;DB에&amp;nbsp;저장하면&amp;nbsp;된다. &lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;# 11.8 RHF Refactor&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;react-hook-form을 이용하여 코드를 &lt;u&gt;refactoring&lt;/u&gt; 하는 과정 &lt;br /&gt;흐름은 유지하면서 코드만 고치는 부분이 많으므로 복습 필요&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;# 12.1 Intercepting Routes&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;폴더명을 &quot;&lt;span style=&quot;color: #ee2323;&quot;&gt;(..)라우트명&lt;/span&gt;&quot;과 같이 작성하여 &lt;u&gt;다른 라우트로의 request를 intercept&lt;/u&gt; 해 올 수 있다. &lt;br /&gt;이렇게&amp;nbsp;될&amp;nbsp;경우&amp;nbsp;상대&amp;nbsp;경로로&amp;nbsp;폴더명을&amp;nbsp;지정한&amp;nbsp;폴더의&amp;nbsp;코드가&amp;nbsp;먼저&amp;nbsp;실행되고,&amp;nbsp;새로고침을&amp;nbsp;하고&amp;nbsp;나서는&amp;nbsp;절대&amp;nbsp;경로로&amp;nbsp;해당&amp;nbsp;위치에&amp;nbsp;있는&amp;nbsp;폴더의&amp;nbsp;코드가&amp;nbsp;실행된다. &lt;br /&gt;이를&amp;nbsp;활용하여&amp;nbsp;modal&amp;nbsp;창을&amp;nbsp;구현할&amp;nbsp;수&amp;nbsp;있다. &lt;br /&gt;&lt;br /&gt;그렇다면 현재 경로에 있는 a라는 라우트를 intercept 하려면? &lt;br /&gt;&amp;rarr; &lt;span style=&quot;color: #ee2323;&quot;&gt;(.)a&lt;/span&gt; 폴더를 하나 더 작성해서 page.tsx를 작성해주면 된다. &lt;br /&gt;&lt;br /&gt;(...)은&amp;nbsp;root&amp;nbsp;directory까지&amp;nbsp;밖으로&amp;nbsp;이동하는&amp;nbsp;것을&amp;nbsp;뜻한다. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;# 12.3 Parallel Routes&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 route의 page가 동시에 렌더링될 수 있도록 해 준다. &lt;br /&gt;slot:&amp;nbsp;parallel&amp;nbsp;route로&amp;nbsp;지정하려면&amp;nbsp;route의&amp;nbsp;폴더명의&amp;nbsp;맨&amp;nbsp;앞에&amp;nbsp;@&amp;nbsp;기호를&amp;nbsp;붙이면&amp;nbsp;된다.&amp;nbsp;이를&amp;nbsp;slot이라고&amp;nbsp;한다. &lt;br /&gt;&lt;br /&gt;구현된&amp;nbsp;parallel&amp;nbsp;route&amp;nbsp;page는&amp;nbsp;해당&amp;nbsp;폴더들을&amp;nbsp;포함하는&amp;nbsp;폴더의&amp;nbsp;layout.tsx에서&amp;nbsp;인자로&amp;nbsp;받아서&amp;nbsp;렌더링해&amp;nbsp;줄&amp;nbsp;수&amp;nbsp;있다. &lt;br /&gt;&lt;br /&gt;주의할&amp;nbsp;점은,&amp;nbsp;route가&amp;nbsp;redirect&amp;nbsp;되는&amp;nbsp;것도&amp;nbsp;고려해&amp;nbsp;주어야&amp;nbsp;한다. &lt;br /&gt;예를&amp;nbsp;들어&amp;nbsp;로그인하지&amp;nbsp;않은&amp;nbsp;사용자는&amp;nbsp;&quot;/&quot;로&amp;nbsp;이동하고&amp;nbsp;로그인한&amp;nbsp;사용자는&amp;nbsp;&quot;/home&quot;으로&amp;nbsp;이동한다면&amp;nbsp;이&amp;nbsp;둘을&amp;nbsp;모두&amp;nbsp;고려하여&amp;nbsp;parallel&amp;nbsp;route&amp;nbsp;page를&amp;nbsp;둘&amp;nbsp;다&amp;nbsp;작성해&amp;nbsp;주어야&amp;nbsp;layout.tsx에서&amp;nbsp;인자를&amp;nbsp;받을&amp;nbsp;때&amp;nbsp;404&amp;nbsp;에러가&amp;nbsp;발생하지&amp;nbsp;않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;# 12.4 Default Routes&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의&amp;nbsp;내용처럼&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;parallel&amp;nbsp;route&lt;/span&gt;가&amp;nbsp;match&amp;nbsp;되는&amp;nbsp;route가&amp;nbsp;없을&amp;nbsp;경우,&amp;nbsp;404&amp;nbsp;에러가&amp;nbsp;발생하게&amp;nbsp;된다. &lt;br /&gt;이를&amp;nbsp;피하기&amp;nbsp;위해서는&amp;nbsp;위의&amp;nbsp;내용처럼&amp;nbsp;각각의&amp;nbsp;parallel&amp;nbsp;route&amp;nbsp;page들을&amp;nbsp;만들어주는&amp;nbsp;방법도&amp;nbsp;있겠지만,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;default&amp;nbsp;routes를&amp;nbsp;사용하면&amp;nbsp;사전에&amp;nbsp;지정하지&amp;nbsp;않은&amp;nbsp;모든&amp;nbsp;route에&amp;nbsp;대해&amp;nbsp;렌더링할&amp;nbsp;component를&amp;nbsp;지정해&amp;nbsp;줄&amp;nbsp;수&amp;nbsp;있다. &lt;br /&gt;&lt;br /&gt;parallel&amp;nbsp;route&amp;nbsp;폴더&amp;nbsp;안에&amp;nbsp;&quot;&lt;span style=&quot;color: #ee2323;&quot;&gt;default.tsx&lt;/span&gt;&quot;라는&amp;nbsp;이름의&amp;nbsp;컴포넌트&amp;nbsp;파일을&amp;nbsp;생성하면,&amp;nbsp;route가&amp;nbsp;match&amp;nbsp;되지&amp;nbsp;않는&amp;nbsp;경우&amp;nbsp;해당&amp;nbsp;컴포넌트를&amp;nbsp;렌더링해&amp;nbsp;준다. &lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;+ Code Challenge&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;Button&amp;nbsp;컴포넌트&amp;nbsp;분리하여&amp;nbsp;use&amp;nbsp;client&amp;nbsp;사용하지&amp;nbsp;않아도&amp;nbsp;되도록&amp;nbsp;만들&amp;nbsp;것 &lt;br /&gt;modal에&amp;nbsp;이미지와&amp;nbsp;product에&amp;nbsp;대한&amp;nbsp;정보&amp;nbsp;DB에서&amp;nbsp;받아와서&amp;nbsp;렌더링하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>웹 개발/NextJS</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/660</guid>
      <comments>https://restudycafe.tistory.com/660#entry660comment</comments>
      <pubDate>Mon, 29 Apr 2024 16:35:20 +0900</pubDate>
    </item>
    <item>
      <title>Flutter로 웹툰 앱 만들기: 스터디 필기 내용 정리</title>
      <link>https://restudycafe.tistory.com/659</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;widget&lt;/span&gt;:&amp;nbsp;UI를&amp;nbsp;구성하는&amp;nbsp;블록 &lt;br /&gt;ex)&amp;nbsp;Center:&amp;nbsp;child를&amp;nbsp;가운데로&amp;nbsp;오게&amp;nbsp;하는&amp;nbsp;widget&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;widget을&amp;nbsp;만들기&amp;nbsp;위해서는&amp;nbsp;flutter에&amp;nbsp;있는&amp;nbsp;3개의&amp;nbsp;&lt;u&gt;core&amp;nbsp;widget&amp;nbsp;중&amp;nbsp;하나를&amp;nbsp;extend&lt;/u&gt;&amp;nbsp;받아서&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;있다. &lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;StatelessWidget&lt;/span&gt;:&amp;nbsp;정적&amp;nbsp;UI&amp;nbsp;/&amp;nbsp;StatefulWidget:&amp;nbsp;동적&amp;nbsp;UI&amp;nbsp;(상태가&amp;nbsp;변경되는&amp;nbsp;UI) &lt;br /&gt;&lt;br /&gt;모든&amp;nbsp;widget은&amp;nbsp;build&amp;nbsp;메서드를&amp;nbsp;포함해야&amp;nbsp;한다. &lt;br /&gt;build&amp;nbsp;메서드:&amp;nbsp;widget의&amp;nbsp;상태가&amp;nbsp;변경될&amp;nbsp;때마다&amp;nbsp;호출되어&amp;nbsp;UI를&amp;nbsp;렌더링 &lt;br /&gt;&lt;br /&gt;root&amp;nbsp;widget에는&amp;nbsp;2개의&amp;nbsp;옵션이&amp;nbsp;있다. &lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;material&amp;nbsp;앱&lt;/span&gt;(from&amp;nbsp;&lt;u&gt;google&lt;/u&gt;)&amp;nbsp;&amp;gt;&amp;nbsp;cupertino&amp;nbsp;앱(from&amp;nbsp;apple) &lt;br /&gt;&lt;br /&gt;scaffold: &lt;u&gt;화면을 구성하는 구조&lt;/u&gt; &lt;br /&gt;모든&amp;nbsp;화면은&amp;nbsp;scaffold를&amp;nbsp;가져야&amp;nbsp;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;stateful&amp;nbsp;widget&lt;/b&gt;:&amp;nbsp;상태에&amp;nbsp;따라&amp;nbsp;데이터를&amp;nbsp;변경되면,&amp;nbsp;변화를&amp;nbsp;UI에&amp;nbsp;실시간으로&amp;nbsp;반영할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;widget &lt;br /&gt;&lt;br /&gt;&lt;u&gt;변경된&amp;nbsp;데이터를&amp;nbsp;UI에&amp;nbsp;업데이트하기&amp;nbsp;위해서는&lt;/u&gt;&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;setState()&lt;/span&gt;&amp;nbsp;함수를&amp;nbsp;사용해야&amp;nbsp;한다.&amp;nbsp;setState()&amp;nbsp;함수를&amp;nbsp;호출하면&amp;nbsp;build()&amp;nbsp;메서드를&amp;nbsp;다시&amp;nbsp;실행된다. &lt;br /&gt;ex&amp;nbsp;)&amp;nbsp;void&amp;nbsp;onClicked()&amp;nbsp;{&amp;nbsp;setState(()&amp;nbsp;{&amp;nbsp;counter++;&amp;nbsp;});&amp;nbsp;}&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;또는&amp;nbsp;다음과&amp;nbsp;같이&amp;nbsp;작성해도&amp;nbsp;UI가&amp;nbsp;업데이트&amp;nbsp;된다. &lt;br /&gt;ex&amp;nbsp;)&amp;nbsp;void&amp;nbsp;onClicked()&amp;nbsp;{&amp;nbsp;counter++;&amp;nbsp;setState(()&amp;nbsp;{});&amp;nbsp;} &lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;of()&lt;/span&gt;&amp;nbsp;메서드:&amp;nbsp;Theme.of(context)는&amp;nbsp;BuildContext인&amp;nbsp;context에서&amp;nbsp;&lt;u&gt;조상&amp;nbsp;중&amp;nbsp;가장&amp;nbsp;가까운&amp;nbsp;Theme&amp;nbsp;widget&lt;/u&gt;을&amp;nbsp;찾아&amp;nbsp;데이터에&amp;nbsp;접근한다. &lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;initState()&lt;/span&gt;&amp;nbsp;메서드:&amp;nbsp;widget이&amp;nbsp;&lt;u&gt;최초로&amp;nbsp;생성되었을&amp;nbsp;때&amp;nbsp;한&amp;nbsp;번만&amp;nbsp;호출&lt;/u&gt;되는&amp;nbsp;메서드 &lt;br /&gt;잘&amp;nbsp;안&amp;nbsp;쓰이지만,&amp;nbsp;super.initState()와&amp;nbsp;같이&amp;nbsp;부모&amp;nbsp;클래스까지&amp;nbsp;같이&amp;nbsp;초기화를&amp;nbsp;해&amp;nbsp;줄&amp;nbsp;수&amp;nbsp;있다. &lt;br /&gt;&lt;br /&gt;dispose()&amp;nbsp;메서드:&amp;nbsp;widget이&amp;nbsp;스크린에서&amp;nbsp;제거될&amp;nbsp;때&amp;nbsp;호출되는&amp;nbsp;메서드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Flutter나&amp;nbsp;Dart의&amp;nbsp;공식&amp;nbsp;패키지&amp;nbsp;저장소는&amp;nbsp;&lt;u&gt;pub.dev&lt;/u&gt;이다. &lt;br /&gt;패키지는&amp;nbsp;&lt;u&gt;flutter&amp;nbsp;pub&amp;nbsp;add&amp;nbsp;&quot;패키지명&quot;&lt;/u&gt;&amp;nbsp;명령어를&amp;nbsp;사용하여&amp;nbsp;설치한다. &lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Future&lt;/b&gt;&lt;/span&gt;:&amp;nbsp;flutter에서&amp;nbsp;비동기&amp;nbsp;작업을&amp;nbsp;수행하고&amp;nbsp;결과를&amp;nbsp;반환하는&amp;nbsp;객체 &lt;br /&gt;Future&amp;nbsp;객체를&amp;nbsp;반환받으려면&amp;nbsp;&lt;u&gt;await&lt;/u&gt;을&amp;nbsp;사용해&amp;nbsp;주어야&amp;nbsp;한다. &lt;br /&gt;&lt;br /&gt;Future&amp;nbsp;객체를&amp;nbsp;이용해&amp;nbsp;data를&amp;nbsp;fetch&amp;nbsp;할&amp;nbsp;때는&amp;nbsp;setState()를&amp;nbsp;사용할&amp;nbsp;필요가&amp;nbsp;없다. &lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;FutureBuilder&lt;/span&gt;라는&amp;nbsp;widget을&amp;nbsp;이용하면,&amp;nbsp;StatelessWidget으로도&amp;nbsp;반환된&amp;nbsp;Future&amp;nbsp;객체의&amp;nbsp;데이터를&amp;nbsp;전달해줄&amp;nbsp;수&amp;nbsp;있다. &lt;br /&gt;(future:&amp;nbsp;Future&amp;nbsp;객체&amp;nbsp;이름,&amp;nbsp;&lt;u&gt;builder:&amp;nbsp;(context,&amp;nbsp;snapshot)&amp;nbsp;{&amp;nbsp;함수&amp;nbsp;}&lt;/u&gt;) &lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;ListView&lt;/span&gt;:&amp;nbsp;여러&amp;nbsp;개의&amp;nbsp;항목들을&amp;nbsp;나열해서&amp;nbsp;볼&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;widget &lt;br /&gt;ListView.&lt;span style=&quot;color: #ee2323;&quot;&gt;builder&lt;/span&gt;:&amp;nbsp;&lt;u&gt;infiniteScroll&lt;/u&gt;&amp;nbsp;등의&amp;nbsp;기능을&amp;nbsp;구현할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;최적화된&amp;nbsp;ListView &lt;br /&gt;ListView.&lt;span style=&quot;color: #ee2323;&quot;&gt;separator&lt;/span&gt;:&amp;nbsp;ListView.builder에&amp;nbsp;separatorBuilder라는&amp;nbsp;추가로&amp;nbsp;인자를&amp;nbsp;가진다. &lt;br /&gt;&lt;br /&gt;Container widget에서, clipBehavior 속성을 통해 자식의 부모 영역 침범을 제어할 수 있다. (ex: clipBehavior: Clip.hardEdge)&lt;br /&gt;&lt;br /&gt;Flutter에서&amp;nbsp;Screen을&amp;nbsp;이동하는&amp;nbsp;법:&amp;nbsp;&lt;b&gt;Navigator&lt;/b&gt; &lt;br /&gt;Navigator는&amp;nbsp;&lt;u&gt;context&lt;/u&gt;와&amp;nbsp;&lt;u&gt;route&lt;/u&gt;를&amp;nbsp;필요로&amp;nbsp;한다.&amp;nbsp;(Navigator.push(context,&amp;nbsp;route)) &lt;br /&gt;route는&amp;nbsp;&lt;u&gt;widget을&amp;nbsp;스크린처럼&amp;nbsp;보이도록&lt;/u&gt;&amp;nbsp;한다.&amp;nbsp; &lt;br /&gt;route&amp;nbsp;자리에는&amp;nbsp;MaterialPageRoute와&amp;nbsp;같은&amp;nbsp;클래스들이&amp;nbsp;들어간다. &lt;br /&gt;&lt;u&gt;fullscreenDialog&lt;/u&gt;:&amp;nbsp;card&amp;nbsp;&amp;rarr;&amp;nbsp;full&amp;nbsp;screen&amp;nbsp;(옆으로&amp;nbsp;넘겨서&amp;nbsp;닫는&amp;nbsp;것이&amp;nbsp;아닌,&amp;nbsp;밑에서&amp;nbsp;화면이&amp;nbsp;팝업됨) &lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;Hero&lt;/span&gt;&amp;nbsp;widget:&amp;nbsp;두&amp;nbsp;개의&amp;nbsp;widget&amp;nbsp;&lt;u&gt;화면을&amp;nbsp;애니메이션으로&amp;nbsp;전환&lt;/u&gt;하게&amp;nbsp;해주는&amp;nbsp;widget &lt;br /&gt;hero&amp;nbsp;widget을&amp;nbsp;두&amp;nbsp;widget에&amp;nbsp;사용하고,&amp;nbsp;같은&amp;nbsp;tag&amp;nbsp;값을&amp;nbsp;주면&amp;nbsp;된다. &lt;br /&gt;&lt;br /&gt;Future&amp;nbsp;객체는&amp;nbsp;constructor로&amp;nbsp;초기화할&amp;nbsp;수는&amp;nbsp;없으므로,&amp;nbsp;이를&amp;nbsp;초기화할&amp;nbsp;때는&amp;nbsp;&lt;u&gt;late&amp;nbsp;modifier&lt;/u&gt;가&amp;nbsp;유용하다. &lt;br /&gt;&lt;br /&gt;Flutter에서&amp;nbsp;앱&amp;nbsp;내에서&amp;nbsp;브라우저를&amp;nbsp;열도록&amp;nbsp;하는&amp;nbsp;방법:&amp;nbsp;url_launcher&amp;nbsp;패키지를&amp;nbsp;설치하여&amp;nbsp;이용하면&amp;nbsp;된다. &lt;br /&gt;&lt;br /&gt;앱&amp;nbsp;내에서&amp;nbsp;모바일&amp;nbsp;기기에&amp;nbsp;데이터를&amp;nbsp;저장하는&amp;nbsp;방법:&amp;nbsp;shared_preference&amp;nbsp;패키지를&amp;nbsp;사용하면&amp;nbsp;된다. &lt;br /&gt;&lt;br /&gt;빌드하기&amp;nbsp;전에,&amp;nbsp;인터넷&amp;nbsp;권한&amp;nbsp;문제&amp;nbsp;해결을&amp;nbsp;해야&amp;nbsp;한다. &lt;br /&gt;Poject&amp;nbsp;뷰&amp;nbsp;&amp;gt;&amp;nbsp;android&amp;nbsp;&amp;gt;&amp;nbsp;app&amp;nbsp;&amp;gt;&amp;nbsp;src&amp;nbsp;&amp;gt;&amp;nbsp;main&amp;nbsp;&amp;gt;&amp;nbsp;AndroidManifest.xml에서, &lt;br /&gt;&amp;lt;application&amp;gt;&amp;nbsp;태그&amp;nbsp;바로&amp;nbsp;윗&amp;nbsp;줄에&amp;nbsp;다음의&amp;nbsp;코드를&amp;nbsp;입력하여&amp;nbsp;권한을&amp;nbsp;추가한다. &lt;br /&gt;&amp;lt;uses-permission&amp;nbsp;android:name=&quot;android.permission.INTERNET&quot;&amp;nbsp;/&amp;gt; &lt;br /&gt;&lt;br /&gt;apk&amp;nbsp;빌드&amp;nbsp;:&amp;nbsp;터미널에&amp;nbsp;flutter&amp;nbsp;build&amp;nbsp;apk&amp;nbsp;--release&amp;nbsp;--target-platform=android-arm64 &lt;br /&gt;빌드&amp;nbsp;경로:&amp;nbsp;[Project&amp;nbsp;Forder]/build/app/outputs/apk/release/app-release.apk&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>웹 개발</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/659</guid>
      <comments>https://restudycafe.tistory.com/659#entry659comment</comments>
      <pubDate>Mon, 29 Apr 2024 16:21:16 +0900</pubDate>
    </item>
    <item>
      <title>NextJS 개념 정리 + 영화 정보 사이트 만들고 vercel로 배포하기 (모든 과정 요약 정리)</title>
      <link>https://restudycafe.tistory.com/658</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스트에서는 &lt;b&gt;NextJS&lt;/b&gt;가 무엇인지에 대해 알아보고, &lt;b&gt;NextJS를&lt;/b&gt; 이용하여 간단한 영화 정보 사이트를 만들고 실제 웹사이트를 배포하는 과정까지 수행해 보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;완성 결과 미리보기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 완성된 웹사이트의 형태를 같이 보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;nextjs-movie-app-gif-800.gif&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;425&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLV8C6/btsF10yvoH4/eHj854ISs9hZuEYQwDhJlk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLV8C6/btsF10yvoH4/eHj854ISs9hZuEYQwDhJlk/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLV8C6/btsF10yvoH4/eHj854ISs9hZuEYQwDhJlk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bLV8C6/btsF10yvoH4/eHj854ISs9hZuEYQwDhJlk/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;425&quot; data-filename=&quot;nextjs-movie-app-gif-800.gif&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;425&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;686&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5hhDB/btsF0bhaOhL/Q9brpkKgnb4pQS5xxXSpSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5hhDB/btsF0bhaOhL/Q9brpkKgnb4pQS5xxXSpSk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5hhDB/btsF0bhaOhL/Q9brpkKgnb4pQS5xxXSpSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5hhDB%2FbtsF0bhaOhL%2FQ9brpkKgnb4pQS5xxXSpSk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;686&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;686&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;API를 제공하는, 데이터가 저장된 사이트로부터 데이터를 잘 fetch 해 와서 정보를 잘 나타내어주는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주의깊게 살펴볼 부분은 렌더링이 진행되는 과정에서, &lt;u&gt;먼저 로딩이 끝난 컴포넌트부터 렌더링이 부분적으로 완료&lt;/u&gt;될 수 있다는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(물론 이 부분은 NextJS만의 기능이 아닌 React의 기능을 이용한 것이지만, 이러한 컴포넌트별 렌더링 기능을 포함하여 페이지의 &lt;span style=&quot;color: #ee2323;&quot;&gt;빠른 로딩을 위한 다양한 기능이 사용되므로, 더 좋은 사용자 경험을 제공&lt;/span&gt;할 수 있습니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;NextJS와 Server Side Rendering&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NextJS는 React의 application을 구축하는 것을 도와주는 프레임워크로, &lt;b&gt;Server Side Rendering&lt;/b&gt;(SSR, Server Side Rendering)이라는 페이지 로딩 시간을 줄여주는 기능을 가지고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NextJS는 application을 render 하는 방법으로, '&lt;span style=&quot;color: #ee2323;&quot;&gt;Server Side Rendering&lt;/span&gt;'이라는 방법을 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SSR이 일어나는 과정은 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;① &lt;u&gt;NextJS가 서버(백엔드)에서 Javascript &amp;rarr; HTML로 렌더링을 한 다음, 이 HTML 코드를 브라우저에 전달해 줍니다. &lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 주목할 점은, 코드는 HTML의 형식으로 전달되기 때문에 페이지에 Javascript가 적용되지 않은 상태여도 렌더링이 정상적으로 작동한다는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;② 그 다음 &lt;u&gt;프레임워크가 페이지에 React application을 추가합니다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 기능은 각 Component에 해당하는 파일의 맨 위에 &quot;use client&quot;; 라는 코드를 작성하여 선택적으로 추가할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 use client란, 이 Component는 클라이언트에서 interactive 해야 함을 의미합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게 되면, 기존에 로드된 HTML 페이지는 그대로 있는 상태로, 여기에 이벤트 리스너 등이 추가되는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 이를 (사용자가 최초 HTML을 본 후) '&lt;span style=&quot;color: #ee2323;&quot;&gt;Hydration이 일어난다&lt;/span&gt;'라고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;NextJS로 영화 정보 사이트 제작하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 저는 NextJS 프로젝트를 작성하여 아래와 같은 Repository에 push 해 두었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;전체적인 프로젝트 코드는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;u&gt;노마드코더의 'NextJS 시작하기' 코스&lt;/u&gt;를 통해 학습하면서 작성하였습니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1711129973093&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - yeohj0710/NextJS-movie-app: movie application built using NextJS&quot; data-og-description=&quot;movie application built using NextJS. Contribute to yeohj0710/NextJS-movie-app development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/yeohj0710/NextJS-movie-app&quot; data-og-url=&quot;https://github.com/yeohj0710/NextJS-movie-app&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/eonuQg/hyVDChvuua/StBitYiIV6MbYKL23JX4d0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/yeohj0710/NextJS-movie-app&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/yeohj0710/NextJS-movie-app&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/eonuQg/hyVDChvuua/StBitYiIV6MbYKL23JX4d0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - yeohj0710/NextJS-movie-app: movie application built using NextJS&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;movie application built using NextJS. Contribute to yeohj0710/NextJS-movie-app development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소스 코드는 위의 Repository에서 참고하시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(NextJS의 프로젝트 구성에 대한 설명과 코드에 대한 설명은 이후에 추가할 예정입니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 포스트에서는 '배포'에 대한 부분을 조금 더 중점적으로 다룹니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;NextJS 프로젝트 배포하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작성이 완료된 프로젝트는 Vercel에서 무료로 배포할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &lt;b&gt;Vercel&lt;/b&gt;은 &lt;u&gt;NextJS를 개발한 기업&lt;/u&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹사이트 배포를 위해, 'vercel.com'으로 이동해 주시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1120&quot; data-origin-height=&quot;557&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OvECk/btsF1z897Gm/9QJR01J5cUzktXo2o1v0m1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OvECk/btsF1z897Gm/9QJR01J5cUzktXo2o1v0m1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OvECk/btsF1z897Gm/9QJR01J5cUzktXo2o1v0m1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOvECk%2FbtsF1z897Gm%2F9QJR01J5cUzktXo2o1v0m1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;701&quot; height=&quot;349&quot; data-origin-width=&quot;1120&quot; data-origin-height=&quot;557&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;vercel의 메인 페이지로 들어가서, 중앙에 보이는 'Start Deploying'을 눌러줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;918&quot; data-origin-height=&quot;755&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MjjEX/btsF0kkG0a5/YP4JE4wC5FMj0ueVh2ODj0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MjjEX/btsF0kkG0a5/YP4JE4wC5FMj0ueVh2ODj0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MjjEX/btsF0kkG0a5/YP4JE4wC5FMj0ueVh2ODj0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMjjEX%2FbtsF0kkG0a5%2FYP4JE4wC5FMj0ueVh2ODj0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;562&quot; height=&quot;462&quot; data-origin-width=&quot;918&quot; data-origin-height=&quot;755&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'Continue with Github'를 선택합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Github에 프로젝트를 업로드 한 후, 해당 Repository를 vercel에 연결하면 vercel에서 자동으로 배포를 진행하고 도메인을 제공해 주는 방식으로 배포가 진행될 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;790&quot; data-origin-height=&quot;310&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dEZcVV/btsF1KvU5zf/PY3D4SSjKVquYqV6C3QACK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dEZcVV/btsF1KvU5zf/PY3D4SSjKVquYqV6C3QACK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dEZcVV/btsF1KvU5zf/PY3D4SSjKVquYqV6C3QACK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdEZcVV%2FbtsF1KvU5zf%2FPY3D4SSjKVquYqV6C3QACK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;622&quot; height=&quot;244&quot; data-origin-width=&quot;790&quot; data-origin-height=&quot;310&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Github 계정 인증을 진행한 이후에, NextJS 프로젝트가 push 되어 있는 Repository를 선택해 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1161&quot; data-origin-height=&quot;684&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dMEzOa/btsF2ue1mqW/95vIilW26MtrXxGssesvj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dMEzOa/btsF2ue1mqW/95vIilW26MtrXxGssesvj1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dMEzOa/btsF2ue1mqW/95vIilW26MtrXxGssesvj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdMEzOa%2FbtsF2ue1mqW%2F95vIilW26MtrXxGssesvj1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;728&quot; height=&quot;429&quot; data-origin-width=&quot;1161&quot; data-origin-height=&quot;684&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주의할 점은 이 부분 정도인데, vercel에서 NextJS 프로젝트를 배포할 때 미리 default 값으로 지정해 둔 명령어에 맞게 package.json의 scripts들을 맞춰서 작성해 두어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또는 Vercel 페이지에서 직접 명령어를 수정하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;718&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7bAnF/btsF13hGkUA/l73K9os4pMuxLXBq8aKhbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7bAnF/btsF13hGkUA/l73K9os4pMuxLXBq8aKhbK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7bAnF/btsF13hGkUA/l73K9os4pMuxLXBq8aKhbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7bAnF%2FbtsF13hGkUA%2Fl73K9os4pMuxLXBq8aKhbK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;807&quot; height=&quot;377&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;718&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배포가 완료되면 위의 이미지와 같이 초록색 원이 뜨면서 'Ready'가 나타납니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;564&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QlOB0/btsF1bt4VdC/luMg3iYKezDC8712AgIwQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QlOB0/btsF1bt4VdC/luMg3iYKezDC8712AgIwQ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QlOB0/btsF1bt4VdC/luMg3iYKezDC8712AgIwQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQlOB0%2FbtsF1bt4VdC%2FluMg3iYKezDC8712AgIwQ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;386&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;564&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'Project' 탭에서 deployment 결과를 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빨간 네모 박스를 친 부분을 클릭하면, 특정 형식을 벗어나지 않는 선에서 도메인을 직접 지정할 수도 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;686&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhoPPw/btsF1rcizrS/hf5HdHR9wKfe6aHKNfjxp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhoPPw/btsF1rcizrS/hf5HdHR9wKfe6aHKNfjxp1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhoPPw/btsF1rcizrS/hf5HdHR9wKfe6aHKNfjxp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhoPPw%2FbtsF1rcizrS%2Fhf5HdHR9wKfe6aHKNfjxp1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;744&quot; height=&quot;399&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;686&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성된 도메인으로 이동해 보면, build와 배포가 정상적으로 완료되어 인터넷으로 정상 접속 및 이용이 가능한 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 해서 NextJS가 무엇인지 알아보고, NextJS를 이용해 영화 정보 웹사이트를 제작 및 배포까지의 과정을 간단하게 다루어보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>웹 개발/NextJS</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/658</guid>
      <comments>https://restudycafe.tistory.com/658#entry658comment</comments>
      <pubDate>Sat, 23 Mar 2024 03:05:49 +0900</pubDate>
    </item>
    <item>
      <title>Firebase 나만의 소셜 미디어 사이트 만들고 배포하기 (모든 과정 설명)</title>
      <link>https://restudycafe.tistory.com/657</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스트에서는 &lt;b&gt;Firebase&lt;/b&gt;를 이용해 나만의 소셜 미디어 서비스를 구현하여 실제 웹사이트로 배포하는 과정까지를 다루어보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;완성 결과 미리보기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 완성한 결과부터 gif 파일로 확인해 봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 도메인이 등록되어 있는, 어디서나 접속 가능한 웹 페이지입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;메인 페이지 살펴보기, 피드 읽고 사진 확대하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;firebase-1.gif&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;425&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nYAah/btsF0baoJXp/kiWCeKTxNHiRkKPKDS1lIK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nYAah/btsF0baoJXp/kiWCeKTxNHiRkKPKDS1lIK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nYAah/btsF0baoJXp/kiWCeKTxNHiRkKPKDS1lIK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/nYAah/btsF0baoJXp/kiWCeKTxNHiRkKPKDS1lIK/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;425&quot; data-filename=&quot;firebase-1.gif&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;425&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;회원가입하기 (계정 생성하기)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;firebase-2.gif&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;425&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boah88/btsF1MgcpJs/ssaVuNWBmIXYGlAvW7PdeK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boah88/btsF1MgcpJs/ssaVuNWBmIXYGlAvW7PdeK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boah88/btsF1MgcpJs/ssaVuNWBmIXYGlAvW7PdeK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/boah88/btsF1MgcpJs/ssaVuNWBmIXYGlAvW7PdeK/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;425&quot; data-filename=&quot;firebase-2.gif&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;425&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;새로운 글 작성하고 이미지 첨부하기, 작성한 글 삭제하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;firebase-3.gif&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;425&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6agAb/btsF04IDwm5/DK7xNkTrEkz4I8KOF8R2C1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6agAb/btsF04IDwm5/DK7xNkTrEkz4I8KOF8R2C1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6agAb/btsF04IDwm5/DK7xNkTrEkz4I8KOF8R2C1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/b6agAb/btsF04IDwm5/DK7xNkTrEkz4I8KOF8R2C1/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;425&quot; data-filename=&quot;firebase-3.gif&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;425&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;프로필 사진 수정하기, 닉네임 수정하기, 수정 후 새로운 글 작성하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;firebase-4.gif&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;425&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uug85/btsFZS9OkQO/kyF80GeuZ1ke5OKVIxKqck/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uug85/btsFZS9OkQO/kyF80GeuZ1ke5OKVIxKqck/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uug85/btsFZS9OkQO/kyF80GeuZ1ke5OKVIxKqck/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/uug85/btsFZS9OkQO/kyF80GeuZ1ke5OKVIxKqck/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;425&quot; data-filename=&quot;firebase-4.gif&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;425&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Firebase&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Firebase는 구글에서 제공하는 데이터베이스 서비스입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DB에 접근하고 데이터를 관리하기 위한 다양한 함수들을 간편하게 제공하기 때문에 코드를 쉽게 구현할 수 있다는 장점이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 일정 데이터 사용량과 DB 용량까지는 무료로 사용할 수 있다는 것과 실제 웹사이트 주소로 간편하게 배포할 수 있다는 것도 매우 큰 장점이라고 생각합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Firebase 프로젝트 생성 및 설정&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 먼저 Firebase 사이트로 접속해줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1711082676924&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;https://console.firebase.google.com/?hl=ko&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1145&quot; data-origin-height=&quot;635&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oHX3d/btsFZumOPMz/YVVs8k5CpJdedBCMwpY7f0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oHX3d/btsFZumOPMz/YVVs8k5CpJdedBCMwpY7f0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oHX3d/btsFZumOPMz/YVVs8k5CpJdedBCMwpY7f0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoHX3d%2FbtsFZumOPMz%2FYVVs8k5CpJdedBCMwpY7f0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;707&quot; height=&quot;392&quot; data-origin-width=&quot;1145&quot; data-origin-height=&quot;635&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'프로젝트 만들기'를 눌러줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;864&quot; data-origin-height=&quot;739&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baSDbD/btsFYk6gJVz/pnK24tz9B1CYoAArGDPC7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baSDbD/btsFYk6gJVz/pnK24tz9B1CYoAArGDPC7K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baSDbD/btsFYk6gJVz/pnK24tz9B1CYoAArGDPC7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaSDbD%2FbtsFYk6gJVz%2FpnK24tz9B1CYoAArGDPC7K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;607&quot; height=&quot;519&quot; data-origin-width=&quot;864&quot; data-origin-height=&quot;739&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 이름을 정해 주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 이름은 나중에 호스팅 서비스를 이용해서 웹사이트 링크가 생성될 때 이름이 그대로 사용되니, 신중하게 결정해줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 가능한 짧고 이해하기 쉬운 프로젝트 이름을 추천합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 yeohj0710x로 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로 Firebase Google 애널리틱스를 사용할 거냐고 묻는데, 저는 사용하지 않겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;409&quot; data-origin-height=&quot;282&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4akwK/btsFZwydqxW/TDecGx6zVB5VCmuCfc1XDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4akwK/btsFZwydqxW/TDecGx6zVB5VCmuCfc1XDK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4akwK/btsFZwydqxW/TDecGx6zVB5VCmuCfc1XDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4akwK%2FbtsFZwydqxW%2FTDecGx6zVB5VCmuCfc1XDK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;350&quot; height=&quot;241&quot; data-origin-width=&quot;409&quot; data-origin-height=&quot;282&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이렇게 Firebase 프로젝트가 생성됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성하는 데 시간이 걸리니 잠시 기다려주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;583&quot; data-origin-height=&quot;371&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xh1l5/btsFX61ib57/vJSh5rdzORJyMpKpIpvwN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xh1l5/btsFX61ib57/vJSh5rdzORJyMpKpIpvwN1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xh1l5/btsFX61ib57/vJSh5rdzORJyMpKpIpvwN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fxh1l5%2FbtsFX61ib57%2FvJSh5rdzORJyMpKpIpvwN1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;533&quot; height=&quot;339&quot; data-origin-width=&quot;583&quot; data-origin-height=&quot;371&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트가 생성되면 메인 화면으로 이동되는데, 우리는 웹사이트를 만들 것이니 웹을 클릭해 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;736&quot; data-origin-height=&quot;599&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLgCrT/btsFZwLKvgV/S8J9DEdU4plHvugLt9b2BK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLgCrT/btsFZwLKvgV/S8J9DEdU4plHvugLt9b2BK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLgCrT/btsFZwLKvgV/S8J9DEdU4plHvugLt9b2BK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLgCrT%2FbtsFZwLKvgV%2FS8J9DEdU4plHvugLt9b2BK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;573&quot; height=&quot;466&quot; data-origin-width=&quot;736&quot; data-origin-height=&quot;599&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앱 닉네임을 설정하고, Firebase 호스팅을 체크해 줍니다. 웹사이트의 실제 배포를 위해 필요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 '앱 등록'을 눌러줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로 'npm install firebase'를 이용해 프로젝트에 firebase를 설치해 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트를 생성하지 않았으면 새로 생성하고, 터미널에서 위 명령어를 입력해 주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;857&quot; data-origin-height=&quot;534&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/t9jWM/btsF0HS5jdf/pu7GFpsIdTjghIOqk7pJRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/t9jWM/btsF0HS5jdf/pu7GFpsIdTjghIOqk7pJRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/t9jWM/btsF0HS5jdf/pu7GFpsIdTjghIOqk7pJRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ft9jWM%2FbtsF0HS5jdf%2Fpu7GFpsIdTjghIOqk7pJRk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;673&quot; height=&quot;419&quot; data-origin-width=&quot;857&quot; data-origin-height=&quot;534&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이런 절차를 거치라는 내용이 나올 건데, firebase.ts라는 파일을 만들어 다음과 같이 작성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1711083269286&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// firebase.ts

import { initializeApp } from &quot;firebase/app&quot;;
import { getAuth } from &quot;firebase/auth&quot;;
import { getFirestore } from &quot;firebase/firestore&quot;;
import { getStorage } from &quot;firebase/storage&quot;;

const firebaseConfig = {
  apiKey: &quot;AIzaSyA9CrbgL6FmJIUYy4CL7Ps3NIEelnMASjE&quot;,
  authDomain: &quot;yeohj0710x.firebaseapp.com&quot;,
  projectId: &quot;yeohj0710x&quot;,
  storageBucket: &quot;yeohj0710x.appspot.com&quot;,
  messagingSenderId: &quot;1070119465029&quot;,
  appId: &quot;1:1070119465029:web:c21ac2cbe88da79c5e732c&quot;,
};

const app = initializeApp(firebaseConfig);

export const auth = getAuth(app);

export const storage = getStorage(app);

export const db = getFirestore(app);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 firebaseConfig 자리에, Google Firebase에서 제공되는 코드를 붙여넣으면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 다음의 명령어를 이용해 Firebase CLI를 설치합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1711083350748&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install -g firebase-tools&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;829&quot; data-origin-height=&quot;622&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dtZzUb/btsFYqecELE/kylPzbXXoTqnNHe8urcEkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dtZzUb/btsFYqecELE/kylPzbXXoTqnNHe8urcEkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dtZzUb/btsFYqecELE/kylPzbXXoTqnNHe8urcEkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdtZzUb%2FbtsFYqecELE%2FkylPzbXXoTqnNHe8urcEkk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;705&quot; height=&quot;529&quot; data-origin-width=&quot;829&quot; data-origin-height=&quot;622&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 firebase login을 수행해 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그인 창이 뜨면 현재 구글 Firebase에 로그인 중인 계정으로 로그인해 주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'firebase init'과 'firebase deploy'는 프로젝트의 코드를 완성한 이후에 수행할 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1263&quot; data-origin-height=&quot;592&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bP3dqI/btsF1rI0X8M/5AQJYkIyDQ4KKZCbzxKj7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bP3dqI/btsF1rI0X8M/5AQJYkIyDQ4KKZCbzxKj7k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bP3dqI/btsF1rI0X8M/5AQJYkIyDQ4KKZCbzxKj7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbP3dqI%2FbtsF1rI0X8M%2F5AQJYkIyDQ4KKZCbzxKj7k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1263&quot; height=&quot;592&quot; data-origin-width=&quot;1263&quot; data-origin-height=&quot;592&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 다시 Firebase 웹 페이지로 돌아와서, Authentication을 눌러줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;574&quot; data-origin-height=&quot;330&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o192C/btsFZBTK0dx/Aa2YRkQjOiskfZkNnlpS00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o192C/btsFZBTK0dx/Aa2YRkQjOiskfZkNnlpS00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o192C/btsFZBTK0dx/Aa2YRkQjOiskfZkNnlpS00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo192C%2FbtsFZBTK0dx%2FAa2YRkQjOiskfZkNnlpS00%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;497&quot; height=&quot;286&quot; data-origin-width=&quot;574&quot; data-origin-height=&quot;330&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'시작하기'를 눌러주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1222&quot; data-origin-height=&quot;552&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6pSyK/btsFYn9NIwl/JFjRKSV6GMK4lzHv1aClEk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6pSyK/btsFYn9NIwl/JFjRKSV6GMK4lzHv1aClEk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6pSyK/btsFYn9NIwl/JFjRKSV6GMK4lzHv1aClEk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6pSyK%2FbtsFYn9NIwl%2FJFjRKSV6GMK4lzHv1aClEk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1222&quot; height=&quot;552&quot; data-origin-width=&quot;1222&quot; data-origin-height=&quot;552&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 로그인 방법을 추가하면 되는데, '이메일/비밀번호'가 가장 간편합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저의 경우에는 Github도 추가하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;299&quot; data-origin-height=&quot;489&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tLsxZ/btsFYDdua4o/mcokz72dTkGeuFbS3JtVUk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tLsxZ/btsFYDdua4o/mcokz72dTkGeuFbS3JtVUk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tLsxZ/btsFYDdua4o/mcokz72dTkGeuFbS3JtVUk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtLsxZ%2FbtsFYDdua4o%2Fmcokz72dTkGeuFbS3JtVUk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;265&quot; height=&quot;433&quot; data-origin-width=&quot;299&quot; data-origin-height=&quot;489&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 탭 왼쪽에서, 빌드 &amp;gt; 'Firestore Database'를 선택해 주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Firestore는 데이터베이스 테이블들이 저장될 공간입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;321&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/P0vG9/btsF0dZbFTZ/AXhvVpLSTTLTyJka0yKJ81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/P0vG9/btsF0dZbFTZ/AXhvVpLSTTLTyJka0yKJ81/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/P0vG9/btsF0dZbFTZ/AXhvVpLSTTLTyJka0yKJ81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FP0vG9%2FbtsF0dZbFTZ%2FAXhvVpLSTTLTyJka0yKJ81%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;474&quot; height=&quot;288&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;321&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마찬가지로 '데이터베이스 만들기'를 눌러줘야 시작할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 다음의 절차를 따라주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 데이터베이스 ID는 (default)로 자동 설정되니 넘어가면 되고, DB 위치는 가장 가까운 'asia-noretheast3 (Seoul)'로 해 줍시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 다음으로 보안 규칙은 일단 '테스트 모드'로 설정해 줍니다. 나중에 바꿀 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. '만들기'를 누르고 기다려주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;482&quot; data-origin-height=&quot;161&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/E5YzF/btsFYE4y0bh/j9xvFnSyOi3srsqBZbRuM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/E5YzF/btsFYE4y0bh/j9xvFnSyOi3srsqBZbRuM0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/E5YzF/btsFYE4y0bh/j9xvFnSyOi3srsqBZbRuM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FE5YzF%2FbtsFYE4y0bh%2Fj9xvFnSyOi3srsqBZbRuM0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;482&quot; height=&quot;161&quot; data-origin-width=&quot;482&quot; data-origin-height=&quot;161&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성이 완료되었으면 Cloud Firestore의 '규칙' 탭으로 이동합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 다음과 같이 작성해 주세요. 이 코드는 나중에 알맞게 수정하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1711084017352&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;rules_version = '2';

service cloud.firestore {
  match /databases/{database}/documents {
    match /tweets/{doc} {
      allow read: if true
      allow create: if request.auth != null
      allow delete, update: if request.auth.uid == resource.data.userId
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;326&quot; data-origin-height=&quot;151&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cb3PF8/btsFYrxtdVW/iKzRTt1vwt7eaP1px9Vz31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cb3PF8/btsFYrxtdVW/iKzRTt1vwt7eaP1px9Vz31/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cb3PF8/btsFYrxtdVW/iKzRTt1vwt7eaP1px9Vz31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcb3PF8%2FbtsFYrxtdVW%2FiKzRTt1vwt7eaP1px9Vz31%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;326&quot; height=&quot;151&quot; data-origin-width=&quot;326&quot; data-origin-height=&quot;151&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 '색인'으로 이동합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'색인 추가'를 누르고, 다음과 같이 작성해 주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 저의 프로젝트에만 적용되는 내용인데, 임시적으로 생성하고 나중에 바꾸면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;804&quot; data-origin-height=&quot;422&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1XoO8/btsF0b8dfnO/KNjpsvHdHhOlQ2ifUKrpWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1XoO8/btsF0b8dfnO/KNjpsvHdHhOlQ2ifUKrpWK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1XoO8/btsF0b8dfnO/KNjpsvHdHhOlQ2ifUKrpWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1XoO8%2FbtsF0b8dfnO%2FKNjpsvHdHhOlQ2ifUKrpWK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;676&quot; height=&quot;355&quot; data-origin-width=&quot;804&quot; data-origin-height=&quot;422&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래로 내려서 쿼리 범위는 '컬렉션'을 선택하고 '색인 만들기'를 클릭합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;색인이 생성되는 데에는 시간이 조금 걸립니다. 기다려 주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;302&quot; data-origin-height=&quot;318&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wDn8o/btsF1qKaEMd/hb07Oot7o5nk1U7kwuvr8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wDn8o/btsF1qKaEMd/hb07Oot7o5nk1U7kwuvr8K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wDn8o/btsF1qKaEMd/hb07Oot7o5nk1U7kwuvr8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwDn8o%2FbtsF1qKaEMd%2Fhb07Oot7o5nk1U7kwuvr8K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;302&quot; height=&quot;318&quot; data-origin-width=&quot;302&quot; data-origin-height=&quot;318&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 좌측 탭에서 'Storage'로 이동해 주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Storage는 이미지와 같은 용량이 큰 데이터들이 저장될 공간입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마찬가지로 '시작하기'를 누르고, '테스트 모드에서 시작' 버튼을 눌러주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지역은 자동으로 설정될 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'완료'를 누르고 버킷이 생성될 때까지 기다려줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;320&quot; data-origin-height=&quot;133&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dalSl0/btsF1kJ6pnK/MfNsSKEWffds7CpLMRJlK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dalSl0/btsF1kJ6pnK/MfNsSKEWffds7CpLMRJlK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dalSl0/btsF1kJ6pnK/MfNsSKEWffds7CpLMRJlK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdalSl0%2FbtsF1kJ6pnK%2FMfNsSKEWffds7CpLMRJlK0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;320&quot; height=&quot;133&quot; data-origin-width=&quot;320&quot; data-origin-height=&quot;133&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성이 완료되었으면, 폴더를 추가하는 버튼을 눌러서 'avatars'와 'tweets' 2개의 폴더를 만들어주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;249&quot; data-origin-height=&quot;215&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4QZ7V/btsF0HTcqGO/RFd1VWawJQat0Qp7vloic0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4QZ7V/btsF0HTcqGO/RFd1VWawJQat0Qp7vloic0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4QZ7V/btsF0HTcqGO/RFd1VWawJQat0Qp7vloic0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4QZ7V%2FbtsF0HTcqGO%2FRFd1VWawJQat0Qp7vloic0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;249&quot; height=&quot;215&quot; data-origin-width=&quot;249&quot; data-origin-height=&quot;215&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 역시 저의 프로젝트에만 해당되는 내용이지만, 나중에 알맞게 수정하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 마찬가지로 '규칙' 탭으로 이동해서 다음과 같이 코드를 작성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1711084447875&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;rules_version = '2';

service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read: if true // request.auth != null
      allow write: if request.auth != null &amp;amp;&amp;amp; request.resource.size &amp;lt; 10 * 1024 * 1024
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'게시'를 누르고 기다려줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 마지막으로 좌측 탭의 '빌드'를 누르고 'Hosting'으로 들어갑니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 아까 firebase tools를 설치했기 때문에, '다음'과 '콘솔로 이동'을 눌러서 일단 이동해줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;프로젝트 코드 작성&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 프로젝트 코드를 작성해 주면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Firebase 공식 문서를 참조하면, Firebase의 다양한 함수들과 사용 방법이 제시되어 있으니 이를 활용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 작성한 프로젝트의 코드는 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;전체적인 프로젝트 코드는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;u&gt;노마드코더의 '트위터 클론코딩' 코스&lt;/u&gt;를 통해 학습하면서 작성했고, 그 이후로 필요한 기능들은 스스로 코딩하여 추가하였습니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1711085403754&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - yeohj0710/Firebase-social-media-app: YHJ   - Social media platform implemented using Firebase&quot; data-og-description=&quot;YHJ   - Social media platform implemented using Firebase - yeohj0710/Firebase-social-media-app&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/yeohj0710/Firebase-social-media-app&quot; data-og-url=&quot;https://github.com/yeohj0710/Firebase-social-media-app&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/hx7fL/hyVDAX9ggv/tAcv4KKOTcIiqth4TvULxK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/yeohj0710/Firebase-social-media-app&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/yeohj0710/Firebase-social-media-app&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/hx7fL/hyVDAX9ggv/tAcv4KKOTcIiqth4TvULxK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - yeohj0710/Firebase-social-media-app: YHJ   - Social media platform implemented using Firebase&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;YHJ   - Social media platform implemented using Firebase - yeohj0710/Firebase-social-media-app&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;271&quot; data-origin-height=&quot;672&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/u6A5L/btsFZBGs32Z/rl6ybUpFSP4UT1pIe7kkTk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/u6A5L/btsFZBGs32Z/rl6ybUpFSP4UT1pIe7kkTk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/u6A5L/btsFZBGs32Z/rl6ybUpFSP4UT1pIe7kkTk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fu6A5L%2FbtsFZBGs32Z%2Frl6ybUpFSP4UT1pIe7kkTk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;271&quot; height=&quot;672&quot; data-origin-width=&quot;271&quot; data-origin-height=&quot;672&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트의 전체적인 구조는 위와 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;836&quot; data-origin-height=&quot;191&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Axi9v/btsFZFPog32/bhfcss0ktW7dDdrQJllxQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Axi9v/btsFZFPog32/bhfcss0ktW7dDdrQJllxQ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Axi9v/btsFZFPog32/bhfcss0ktW7dDdrQJllxQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAxi9v%2FbtsFZFPog32%2Fbhfcss0ktW7dDdrQJllxQ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;792&quot; height=&quot;181&quot; data-origin-width=&quot;836&quot; data-origin-height=&quot;191&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크립트 역시 위와 같이 작성하여 배포 명령어까지 완성하였으면, 이제 실제 웹사이트로의 배포 준비가 끝났습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;실제 웹사이트로 배포하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 코드를 작성한 프로젝트를 실제 웹사이트로 배포해 봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아까 firebase login까지만 진행하고, init과 deploy는 진행하지 않았었는데요, 그 과정을 지금 수행할 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 먼저 다음의 명령어를 통해 firebase 프로젝트 설정을 콘솔에서 진행하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1711118784432&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;firebase init&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;655&quot; data-origin-height=&quot;278&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n6jZ1/btsF3fhmmRm/V1jeMGUEisy2zr3P1mAXDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n6jZ1/btsF3fhmmRm/V1jeMGUEisy2zr3P1mAXDk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n6jZ1/btsF3fhmmRm/V1jeMGUEisy2zr3P1mAXDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn6jZ1%2FbtsF3fhmmRm%2FV1jeMGUEisy2zr3P1mAXDk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;655&quot; height=&quot;278&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;655&quot; data-origin-height=&quot;278&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 firebase에서 콘솔을 통해 몇 가지 질문을 할 텐데, 프로젝트에 알맞은 설정을 해주면 됩니다.&lt;br /&gt;첫 번째 질문에는 'Yes'로 답해 줍니다.&lt;br /&gt;다음으로 프로젝트 설정에서는, 'Hosting: Configure files for Firebase Hosting and (optionally) set up GitHub Action deploys'을 선택해 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 여기서 에러가 발생하는 경우, 다른 계정으로 firebase login이 수행된 상태거나, 또는 다른 프로젝트로 접근이 설정되어 있을 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 계정으로 로그인 되어있는 경우 firebase logout을 입력해 로그아웃을 해 준 이후, 다시 firebase login을 통해 로그인을 해 주면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 프로젝트로 접근이 설정되어있는 경우에는&amp;nbsp; 'firebase use (프로젝트명)'으로 접근할 프로젝트를 변경해 줄 수 있으니 에러가 발생할 경우 시도해 보면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;'What do you want to use as your public directory?'라는 질문에는 'dist'라고 입력해 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐하면, build 명령어를 수행했을 때 dist/ 디렉토리에 파일들이 빌드되기 때문입니다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'single-page app?' 관련 질문에는 'y'로 답해 줍니다.&lt;br /&gt;&lt;br /&gt;'automatic builds &amp;amp; deploys with Github?' 관련 질문에는 'N'으로 답해 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 모든 설정이 끝났고, 진짜로 배포만 남았습니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음의 명령어를 입력하여 배포를 시작해 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1711118692344&quot; class=&quot;dockerfile&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;npm run deploy&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;662&quot; data-origin-height=&quot;273&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xnE9I/btsF2GsTghR/5uXSLt1JxDChk1SMmj3i81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xnE9I/btsF2GsTghR/5uXSLt1JxDChk1SMmj3i81/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xnE9I/btsF2GsTghR/5uXSLt1JxDChk1SMmj3i81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxnE9I%2FbtsF2GsTghR%2F5uXSLt1JxDChk1SMmj3i81%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;662&quot; height=&quot;273&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;662&quot; data-origin-height=&quot;273&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;잠시 기다린 후 위와 같이 호스팅 주소가 나타나면 배포에 성공한 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 링크로 접속해 봅시다.&lt;br /&gt;참고로 firebase에서 같은 프로젝트에 제공하는 도메인은 2가지입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. (도메인 이름).web.app&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. (도메인 이름).firebaseapp.com&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 팁~&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 번째 주소는 도메인이 짧다는 장점이 있지만, 가끔 새로 deploy 했을 때 바로 반영이 안되는 현상이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 내가 배포 후 업데이트된 사항이 반영되었는지 바로 체크하고 싶으면 ~.firebaseapp.com 도메인을 사용하는 것도 좋습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;943&quot; data-origin-height=&quot;1031&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IOHqW/btsF16L7OVn/7JgKwNzlcGuYQMjQaqakT0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IOHqW/btsF16L7OVn/7JgKwNzlcGuYQMjQaqakT0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IOHqW/btsF16L7OVn/7JgKwNzlcGuYQMjQaqakT0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIOHqW%2FbtsF16L7OVn%2F7JgKwNzlcGuYQMjQaqakT0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;622&quot; height=&quot;680&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;943&quot; data-origin-height=&quot;1031&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성된 도메인으로 접속해 보면, 웹사이트가 성공적으로 잘 배포된 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;보너스: 웹사이트 메타 태그(meta 정보) 등록하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지 읽거나 따라오신 분을 위해 웹사이트의 메타 태그를 등록하는 과정을 알려드리겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메타 태그를 등록하면, 카카오톡으로 링크를 공유했을 때 나타나는 미리보기를 원하는 대로 설정할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;659&quot; data-origin-height=&quot;293&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/y6v6P/btsF17dd3rz/vidXJCdBtv3JA3Z5I7nD9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/y6v6P/btsF17dd3rz/vidXJCdBtv3JA3Z5I7nD9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/y6v6P/btsF17dd3rz/vidXJCdBtv3JA3Z5I7nD9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fy6v6P%2FbtsF17dd3rz%2FvidXJCdBtv3JA3Z5I7nD9K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;659&quot; height=&quot;293&quot; data-origin-width=&quot;659&quot; data-origin-height=&quot;293&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 왼쪽과 같이 공유되는 링크에 오른쪽과 같이 내가 원하는 설명과 이미지 미리보기를 붙일 수 있다는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메타 태그를 설정하는 방법은, index.html을 다음과 같이 작성하는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;미리보기에 제공할 정보를 위한 og:url, og:title, og:type, og:image와 같은 다양한 메타 태그를 추가할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고를 위해 제가 작성한 메타 태그 코드를 다음과 같이 첨부합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;미리보기 이미지는 제가 만든 사이트에 업로드한 뒤, 해당 이미지의 주소를 붙여넣었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1711123132942&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!-- index.html --&amp;gt;
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;en&quot;&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;UTF-8&quot; /&amp;gt;
    &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&amp;gt;
    &amp;lt;meta property=&quot;og:url&quot; content=&quot;https://yeohj0710x.web.app/&quot; /&amp;gt;
    &amp;lt;meta property=&quot;og:title&quot; content=&quot;YHJ  &quot; /&amp;gt;
    &amp;lt;meta property=&quot;og:type&quot; content=&quot;website&quot; /&amp;gt;
    &amp;lt;meta
      property=&quot;og:image&quot;
      content=&quot;https://firebasestorage.googleapis.com/v0/b/yeohj0710x.appspot.com/o/tweets%2F1kf9VCWF32SqtUw8SC0XUvnmfeG2-tester123%2FIOsMYA5yaQ5NsWNeazd0?alt=media&amp;amp;token=1ee035c7-2bd1-44b6-aec3-6201c9db9e94&quot;
    /&amp;gt;
    &amp;lt;meta property=&quot;og:description&quot; content=&quot;YHJ  에서 일상을 공유하세요.&quot; /&amp;gt;
    &amp;lt;title&amp;gt;YHJ  &amp;lt;/title&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;div id=&quot;root&quot;&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;script type=&quot;module&quot; src=&quot;/src/main.tsx&quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이를 적용시키기 위해서, 'npm run deploy' 명령어를 통해 다시 배포를 해 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 카카오톡을 통해 링크 이미지 미리보기나 사이트 이름 등 메타 태그가 제대로 적용이 되는지 확인해 봅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;337&quot; data-origin-height=&quot;273&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kFr28/btsFZWjZERH/vwkjuxBXga6ryceyFKnWL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kFr28/btsFZWjZERH/vwkjuxBXga6ryceyFKnWL1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kFr28/btsFZWjZERH/vwkjuxBXga6ryceyFKnWL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkFr28%2FbtsFZWjZERH%2FvwkjuxBXga6ryceyFKnWL1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;337&quot; height=&quot;273&quot; data-origin-width=&quot;337&quot; data-origin-height=&quot;273&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;적용이 잘 되는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 바로 적용이 되지 않는 경우, 카카오톡의 '공유 디버거' 사이트에서 링크를 업로드하고 강제로 캐시를 초기화하여 업데이트할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1711123376524&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;https://developers.kakao.com/tool/debugger/sharing&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 링크로 들어가서, 업데이트 된 페이지 링크를 붙여넣고 캐시 초기화 및 디버그를 수행해 주면 업데이트가 적용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 해서 Firebase를 이용해 나만의 소셜 미디어 사이트 만들고 배포하는 모든 과정을 다루어보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>웹 개발/Firebase</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/657</guid>
      <comments>https://restudycafe.tistory.com/657#entry657comment</comments>
      <pubDate>Fri, 22 Mar 2024 14:32:52 +0900</pubDate>
    </item>
    <item>
      <title>SocketIO 실시간 채팅 사이트 만들고 실제 웹사이트 배포하기</title>
      <link>https://restudycafe.tistory.com/656</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스트에서는 &lt;b&gt;SocketIO&lt;/b&gt;를 이용해 실시간 채팅 사이트를 만들고, 실제 웹사이트 배포까지 하는 과정을 다루어보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 완성된 웹사이트의 작동 화면은 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;SocketIO-practice-image-1.gif&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;319&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LDPJv/btsFFXo3J7D/c7WlYxPSpqzL1nCQ3S76ik/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LDPJv/btsFFXo3J7D/c7WlYxPSpqzL1nCQ3S76ik/img.gif&quot; data-alt=&quot;완성된 웹 페이지의 작동 화면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LDPJv/btsFFXo3J7D/c7WlYxPSpqzL1nCQ3S76ik/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/LDPJv/btsFFXo3J7D/c7WlYxPSpqzL1nCQ3S76ik/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;319&quot; data-filename=&quot;SocketIO-practice-image-1.gif&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;319&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;완성된 웹 페이지의 작동 화면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;HTTP vs WebSocket&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모두들 &lt;b&gt;HTTP&lt;/b&gt;에 대해서는 많이 들어보셨을 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 인터넷 주소 맨 앞에 작성하는 'http'는 &lt;u&gt;클라이언트(우리)가 웹 서버에 요청을 보내고, 서버가 응답을 보내는 하나의 정해진 통신 규칙&lt;/u&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 한글을 사용하는 것과 같이 http라는 프로토콜에 따라 서버에 요청을 보내고 웹 페이지를 받아와서 우리가 화면을 볼 수 있는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;WebSocket&lt;/b&gt;은 HTTP와 비교되는 개념입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP에서 페이지가 업데이트 되려면 클릭을 하거나 페이지를 이동하는 등 새로운 '요청'을 보내야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 WebSocket은 &lt;span style=&quot;color: #ee2323;&quot;&gt;지속적으로 연결을 유지하는 규칙을 가지고 있기 때문에, 실시간으로 데이터를 주고받을 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 채팅을 구현했다고 가정해 봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 통신으로 새로운 채팅이 왔는지 확인을 하기 위해서는, 페이지를 새로고침해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 WebSocket으로 구현된 채팅의 경우에는 페이지를 띄워놓기만 해도 채팅이 업데이트 될 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;SocketIO란?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;SockeIO&lt;/b&gt;&lt;/span&gt;는 &lt;u&gt;WebSocket 기능을 쉽게 구현할 수 있게 해주는 JavaScript 라이브러리&lt;/u&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WebSocket 통신에 필요한 기능들이 많이 구현되어 있어서 쉽게 가져다 쓸 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;백엔드와 프론트엔드 사이에서 호출할 이벤트의 이름들을 직접 정의하고 사용할 수 있다&lt;/span&gt;&lt;/b&gt;는 점, 함수를 포함한 다양한 객체들을 쉽게 주고받을 수 있다는 점이 매우 큰 장점입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;코드 작성하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작성된 전체 코드는 아래의 Github 프로젝트 레포지토리에 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체적인 코드는 &lt;u&gt;노마드코더의 '줌 클론코딩' 코스&lt;/u&gt;를 통해 학습하면서 작성했고, 그 이후로 필요한 기능들은 스스로 코딩하여 추가하였습니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직 코드를 정리하지 않아서 코드 순서를 한눈에 보기 쉽지 않지만, 코드의 양이 크게 많지는 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1710072107703&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - yeohj0710/SocketIO-practice: A project for practicing SocketIO&quot; data-og-description=&quot;A project for practicing SocketIO. Contribute to yeohj0710/SocketIO-practice development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/yeohj0710/SocketIO-practice&quot; data-og-url=&quot;https://github.com/yeohj0710/SocketIO-practice&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/xYVN2/hyVxw9IyIU/dq4XDrC9BAEIHhfvaHhUs1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/yeohj0710/SocketIO-practice&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/yeohj0710/SocketIO-practice&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/xYVN2/hyVxw9IyIU/dq4XDrC9BAEIHhfvaHhUs1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - yeohj0710/SocketIO-practice: A project for practicing SocketIO&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;A project for practicing SocketIO. Contribute to yeohj0710/SocketIO-practice development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 코드를 작성한 파일은 server.js, app.js, home.pug 3개뿐이고 그마저도 다 합쳐서 300줄 이내이므로, SocketIO가 얼마나 간편한 라이브러리인지 알 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심 기능은 &lt;u&gt;io().on(이벤트명, 객체)&lt;/u&gt; 함수라고 생각합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 함수를 이용하면 위에서 언급한대로 이벤트의 이름을 정의하고, 프론트엔드와 백엔드 사이에서 이벤트를 발생시키고 다양한 객체를 실시간으로 전송할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;로컬에서 프로젝트 빌드하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드 작성이 끝났으면 이제 프로젝트를 빌드해 주어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빌드 명령어 'build'와 app 시작 명령어 'start'를 다음과 같이 정의해 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;362&quot; data-origin-height=&quot;124&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dUDAJT/btsFEiVe9kN/nxDH7CAtwYLlDEE7JcpBDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dUDAJT/btsFEiVe9kN/nxDH7CAtwYLlDEE7JcpBDk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dUDAJT/btsFEiVe9kN/nxDH7CAtwYLlDEE7JcpBDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdUDAJT%2FbtsFEiVe9kN%2FnxDH7CAtwYLlDEE7JcpBDk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;362&quot; height=&quot;124&quot; data-origin-width=&quot;362&quot; data-origin-height=&quot;124&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 두 명령어를 각각 실행해서 build와 start가 잘 작동하는지 확인해 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;build 명령어 실행 후에는 &lt;u&gt;최적화된 자바스크립트 코드가 build 폴더에&lt;/u&gt; 들어가 있어야 하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;start 명령어를 실행하면 &lt;span style=&quot;color: #ee2323;&quot;&gt;build 명령어를 통해 빌드된 프로젝트가 정상적으로 실행&lt;/span&gt;이 되어야합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;실제 웹사이트로 배포하기 (Koyeb 이용)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드가 로컬에서 제대로 작동하는 것을 확인했으면 이제 실제 웹사이트 링크로 배포가 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래는 배포에 Heroku를 사용했는데, 유료로 전환된 관계로 대체할만한 플랫폼을 찾은 끝에 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Koyeb&lt;/b&gt;&lt;/span&gt;을 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Koyeb의 장점은 &lt;u&gt;당연히 무료&lt;/u&gt;이고, &lt;u&gt;신용카드 등록을 하지 않을 뿐더러&lt;/u&gt;(즉 사이트가 공격을 받더라도 자동결제 될 일이 없다는 것이죠), &lt;u&gt;배포가 어렵지 않습니다&lt;/u&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1490&quot; data-origin-height=&quot;654&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rJWZU/btsFFnIB8gG/kDMZBhWDoKtjskrrjk2ZYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rJWZU/btsFFnIB8gG/kDMZBhWDoKtjskrrjk2ZYK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rJWZU/btsFFnIB8gG/kDMZBhWDoKtjskrrjk2ZYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrJWZU%2FbtsFFnIB8gG%2FkDMZBhWDoKtjskrrjk2ZYK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1490&quot; height=&quot;654&quot; data-origin-width=&quot;1490&quot; data-origin-height=&quot;654&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Koyeb에 회원가입을 하고, &lt;u&gt;Github에 프로젝트를 업로드한 뒤 github 계정 권한을 받아 해당 프로젝트를 Koyeb과 연결&lt;/u&gt;해 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;556&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/z4Ko3/btsFGM1las3/8p35knYFvJjPUiFipg17w1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/z4Ko3/btsFGM1las3/8p35knYFvJjPUiFipg17w1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/z4Ko3/btsFGM1las3/8p35knYFvJjPUiFipg17w1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fz4Ko3%2FbtsFGM1las3%2F8p35knYFvJjPUiFipg17w1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;754&quot; height=&quot;464&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;556&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;Settings 탭에서 위와 같이 npm 명령어를 똑같이 맞춰줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래야 Koyeb 서버에서 빌드 후 app을 시작할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1484&quot; data-origin-height=&quot;542&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTPSSS/btsFGqEfbKy/GTPkuCZTwD4UzBdqfG08uK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTPSSS/btsFGqEfbKy/GTPkuCZTwD4UzBdqfG08uK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTPSSS/btsFGqEfbKy/GTPkuCZTwD4UzBdqfG08uK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTPSSS%2FbtsFGqEfbKy%2FGTPkuCZTwD4UzBdqfG08uK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1484&quot; height=&quot;542&quot; data-origin-width=&quot;1484&quot; data-origin-height=&quot;542&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Build 완료 후 프로젝트 실행이 정상적으로 완료되면 위와 같이 &lt;b&gt;Active&lt;/b&gt; 표시가 뜹니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 &lt;span style=&quot;color: #ee2323;&quot;&gt;Public URL을 통해 실제로 외부에서 사이트에 접속이 가능한지&lt;/span&gt; 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;961&quot; data-origin-height=&quot;1031&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bisPEz/btsFGn1NX6j/AN2L2kzxtk27jZrapKKD00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bisPEz/btsFGn1NX6j/AN2L2kzxtk27jZrapKKD00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bisPEz/btsFGn1NX6j/AN2L2kzxtk27jZrapKKD00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbisPEz%2FbtsFGn1NX6j%2FAN2L2kzxtk27jZrapKKD00%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;569&quot; height=&quot;610&quot; data-origin-width=&quot;961&quot; data-origin-height=&quot;1031&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;사이트 배포가 성공적으로 완료&lt;/u&gt;되어 정상적으로 작동하는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>웹 개발/SocketIO</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/656</guid>
      <comments>https://restudycafe.tistory.com/656#entry656comment</comments>
      <pubDate>Sun, 10 Mar 2024 21:21:58 +0900</pubDate>
    </item>
    <item>
      <title>Node.js 여러 버전을 설치하고 원하는 버전으로 변경하기 (NVM)</title>
      <link>https://restudycafe.tistory.com/655</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이 포스트에서는 &lt;b&gt;Node.js&lt;/b&gt;의 여러 가지 버전을 설치하고, 또 원하는 버전으로 언제든 변경하는 방법을 다룹니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;NVM(Node Version Manager)이란?&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;525&quot; data-origin-height=&quot;80&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tVJQ6/btsFh7Sq52M/M16jlpsdy9K7UtzLNW0lak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tVJQ6/btsFh7Sq52M/M16jlpsdy9K7UtzLNW0lak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tVJQ6/btsFh7Sq52M/M16jlpsdy9K7UtzLNW0lak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtVJQ6%2FbtsFh7Sq52M%2FM16jlpsdy9K7UtzLNW0lak%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;525&quot; height=&quot;80&quot; data-origin-width=&quot;525&quot; data-origin-height=&quot;80&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다양한 모듈이나 라이브러리를 설치하면 위와 같이 Node.js 버전이 맞지 않아 서로 호환이 되지 않는 상황이 발생할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다고 해서 이 모듈과의 호환성 하나만을 위해 기존의 node 버전을 삭제하고 다시 다른 버전을 설치하는 과정을 반복하는 것은 매우 번거롭습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 경우 &lt;b&gt;NVM(Node Version Manager)&lt;/b&gt;를 이용하면&lt;span style=&quot;color: #ee2323;&quot;&gt; 다양한 버전의 NodeJS를 설치하고 원할 때마다 프로젝트의 버전을 바꾸어 사용&lt;/span&gt;할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;필요한 node.js 버전 확인하고 새로운 버전 설치하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 다음의 링크로 들어가서 원하는 &lt;u&gt;NodeJS의 버전들이 어떤 것들이 있는지&lt;/u&gt; 살펴봅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708826778150&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;https://nodejs.org/en/about/previous-releases&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;420&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dmUrTL/btsFhTGJOjE/45KWBReJErcj0PGC8sTDeK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dmUrTL/btsFhTGJOjE/45KWBReJErcj0PGC8sTDeK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dmUrTL/btsFhTGJOjE/45KWBReJErcj0PGC8sTDeK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdmUrTL%2FbtsFhTGJOjE%2F45KWBReJErcj0PGC8sTDeK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;960&quot; height=&quot;420&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;420&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;필요한 버전을 확인&lt;/span&gt;한 후 다음과 같이 필요한 NodeJS 버전을 추가 설치합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708826844928&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;nvm install {원하는 버전}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;564&quot; data-origin-height=&quot;210&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HQJNZ/btsFffqISwb/WCXxOU5EPqcwbwRvZZE9cK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HQJNZ/btsFffqISwb/WCXxOU5EPqcwbwRvZZE9cK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HQJNZ/btsFffqISwb/WCXxOU5EPqcwbwRvZZE9cK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHQJNZ%2FbtsFffqISwb%2FWCXxOU5EPqcwbwRvZZE9cK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;564&quot; height=&quot;210&quot; data-origin-width=&quot;564&quot; data-origin-height=&quot;210&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 위와 같이 새로운 버전이 추가됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;NVM으로 존재하는 node.js 버전 확인하고 변경하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같은 명령어로 설치되어 &lt;u&gt;존재하는 node.js 버전들의 목록을 확인&lt;/u&gt;할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708826958397&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;nvm list&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;471&quot; data-origin-height=&quot;117&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVgkHZ/btsFjIxWgQ9/rm9ysBBwK1qtMigrZ53nZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVgkHZ/btsFjIxWgQ9/rm9ysBBwK1qtMigrZ53nZ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVgkHZ/btsFjIxWgQ9/rm9ysBBwK1qtMigrZ53nZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVgkHZ%2FbtsFjIxWgQ9%2Frm9ysBBwK1qtMigrZ53nZ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;471&quot; height=&quot;117&quot; data-origin-width=&quot;471&quot; data-origin-height=&quot;117&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 설치된 node.js 버전들이 나타나는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;별표 표시된 버전이 현재 프로젝트에서 사용 중인 버전에 해당합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같은 명령어로 이 &lt;u&gt;프로젝트에서 사용할 node.js의 버전을 변경&lt;/u&gt;할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708827019277&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;nvm use {사용할 node.js 버전}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;334&quot; data-origin-height=&quot;58&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3jeaM/btsFgrqCyeE/hz7eKsQgPSUuHg5Iyk7Zm1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3jeaM/btsFgrqCyeE/hz7eKsQgPSUuHg5Iyk7Zm1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3jeaM/btsFgrqCyeE/hz7eKsQgPSUuHg5Iyk7Zm1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3jeaM%2FbtsFgrqCyeE%2Fhz7eKsQgPSUuHg5Iyk7Zm1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;334&quot; height=&quot;58&quot; data-origin-width=&quot;334&quot; data-origin-height=&quot;58&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 원하는 버전으로 node.js의 버전이 변경된 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>웹 개발</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/655</guid>
      <comments>https://restudycafe.tistory.com/655#entry655comment</comments>
      <pubDate>Sun, 25 Feb 2024 11:11:51 +0900</pubDate>
    </item>
    <item>
      <title>GraphQL 간단한 Query와 Mutation을 구현하고 테스트 해 보기</title>
      <link>https://restudycafe.tistory.com/654</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스트에서는 &lt;b&gt;GraphQL&lt;/b&gt;에서 데이터에 접근하는 &lt;b&gt;Query&lt;/b&gt;와, 데이터를 추가하고 삭제하는 간단한 &lt;b&gt;Mutation&lt;/b&gt;을 구현해 보고 테스트를 해 보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;개요: 구현할 기능&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 구현할 기능은 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Person이라는 객체 타입을 정의하고, 각 Person은 &lt;u&gt;고유한 id, 이름, 나이&lt;/u&gt;를 값으로 가지도록 작성할 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 Person들은 group이라는 배열에 저장됩니다. (실제 프로젝트에서는 group이라는 이름을 가지는 데이터베이스에 저장이 되겠죠?)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Query는 group을 반환받아 &lt;span style=&quot;color: #ee2323;&quot;&gt;전체 Person들을 받아오는 group 쿼리&lt;/span&gt;와, &lt;span style=&quot;color: #ee2323;&quot;&gt;특정 이름을 가진 Person이 있는지 체크하는 person 쿼리&lt;/span&gt;가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 Mutation에는 2가지를 작성할 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt; group에 새로운 Person을 정의하여 추가하는 createPerson&lt;/span&gt;과 &lt;span style=&quot;color: #ee2323;&quot;&gt;특정 이름을 가진 Person을 group에서 제거하는 deletePerson&lt;/span&gt;을 구현할 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;전체 코드 살펴보기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 다음으로 코드를 살펴보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간략한 설명을 위해 한눈에 볼 수 있게끔 모든 typeDefs들과 resolvers들을 한 JavaScript 파일에 작성하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708734106405&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// server.js

import { ApolloServer, gql } from &quot;apollo-server&quot;;

const typeDefs = gql`
  type Person {
    id: ID!
    name: String!
    age: Int!
  }
  type Query {
    group: [Person]
    person(name: String!): Person
  }
  type Mutation {
    createPerson(name: String!, age: Int!): Boolean
    deletePerson(name: String!): Boolean
  }
`;

const group = [
  { id: 1, name: &quot;asdf&quot;, age: 25 },
  { id: 2, name: &quot;qwer&quot;, age: 30 },
];

const resolvers = {
  Query: {
    group: () =&amp;gt; {
      return group;
    },
    person: (_, { name }) =&amp;gt; {
      return group.find((person) =&amp;gt; {
        return person.name === name;
      });
    },
  },
  Mutation: {
    createPerson: (_, { name, age }) =&amp;gt; {
      const newPerson = {
        id: group.length + 1,
        name,
        age,
      };
      group.push(newPerson);
      return true;
    },
    deletePerson: (_, { name }) =&amp;gt; {
      const index = group.findIndex((person) =&amp;gt; person.name == name);
      if (index === -1) return false;
      group.splice(index, 1);
      return true;
    },
  },
};

const server = new ApolloServer({
  typeDefs,
  resolvers,
});

server
  .listen()
  .then(() =&amp;gt; console.log(&quot;Server is running on http://localhost:4000/&quot;));&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;typeDefs 살펴보기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 typeDefs를 살펴볼까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;537&quot; data-origin-height=&quot;362&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lHVnn/btsFhnVgpRT/YBqPb2K9x3psu7CMtFB6L1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lHVnn/btsFhnVgpRT/YBqPb2K9x3psu7CMtFB6L1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lHVnn/btsFhnVgpRT/YBqPb2K9x3psu7CMtFB6L1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlHVnn%2FbtsFhnVgpRT%2FYBqPb2K9x3psu7CMtFB6L1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;537&quot; height=&quot;362&quot; data-origin-width=&quot;537&quot; data-origin-height=&quot;362&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구현할 기능에서 말한 대로, Person 타입을 선언하고 id, name, age 값을 정의해 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 Query와 Mutation에도 각각 위에서 언급한 내용들을 적어줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매개변수가 필요한 Query와 Mutation은 소괄호를 쳐주고 필요한 매개변수들과 타입을 적어주어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반환값의 타입을 적어주는 것도 주의해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;363&quot; data-origin-height=&quot;107&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJdjrk/btsFin1C5vK/at4E1EG0V1r5C1vc3xKPX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJdjrk/btsFin1C5vK/at4E1EG0V1r5C1vc3xKPX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJdjrk/btsFin1C5vK/at4E1EG0V1r5C1vc3xKPX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJdjrk%2FbtsFin1C5vK%2Fat4E1EG0V1r5C1vc3xKPX0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;363&quot; height=&quot;107&quot; data-origin-width=&quot;363&quot; data-origin-height=&quot;107&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 group 배열을 미리 만들어줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 프로젝트에서는 DB가 필요하겠지만, 여기서는 임시로 배열을 선언하여 여기에 데이터를 추가하고 제거하도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;resolvers 살펴보기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로 resolvers를 살펴봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;resolvers에는 실제로 데이터에 접근하거나 수정하는 과정을 수행하는 함수를 구현해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;606&quot; data-origin-height=&quot;586&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6ClXi/btsFhSt0PHn/UNGkR9Xm4w2tPsyYNh4MRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6ClXi/btsFhSt0PHn/UNGkR9Xm4w2tPsyYNh4MRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6ClXi/btsFhSt0PHn/UNGkR9Xm4w2tPsyYNh4MRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6ClXi%2FbtsFhSt0PHn%2FUNGkR9Xm4w2tPsyYNh4MRk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;606&quot; height=&quot;586&quot; data-origin-width=&quot;606&quot; data-origin-height=&quot;586&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Query 부분을 살펴봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;group의 경우에는 전체 배열을 반환해 주면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;person은 같은 이름을 가진 Person을 반환해야 하므로, name 인자를 받아 find 함수를 이용해 동일한 이름을 가진 Person을 반환받아 해당 Person을 반환해 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 Mutation 부분입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;createPerson에는 새로 지정할 Person의 name, age 값이 필요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 새로운 Person 객체를 정의하고, 그 객체를 group에 push 해 주면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성공적으로 처리가 되었음을 알리기 위해 true 값을 마지막에 반환해 주도록 합시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;deletePerson에서는 먼저 해당 name을 가진 Person이 있는지 검색해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 index가 -1이라면 해당 이름을 가진 Person이 없다는 뜻이므로, 아무런 변화도 주지 않고 false를 반환하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 찾았다면 해당 Person을 splice 함수를 이용해 group 배열로부터 제거해 주고, true를 반환합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Query, Mutation 실행해 보기&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;450&quot; data-origin-height=&quot;167&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yOgBS/btsFgo8jDSv/ep9HwoiyOwBAnQL8kSDV4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yOgBS/btsFgo8jDSv/ep9HwoiyOwBAnQL8kSDV4k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yOgBS/btsFgo8jDSv/ep9HwoiyOwBAnQL8kSDV4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyOgBS%2FbtsFgo8jDSv%2Fep9HwoiyOwBAnQL8kSDV4k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;450&quot; height=&quot;167&quot; data-origin-width=&quot;450&quot; data-origin-height=&quot;167&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;npm run 명령어를 터미널에 입력하여 코드를 실행하면 이렇게 localhost:4000에 서버가 열렸다는 메시지를 출력됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;728&quot; data-origin-height=&quot;456&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/200Ag/btsFhVEhCDO/nwL6RZE2a9kO8q9CnJ6qQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/200Ag/btsFhVEhCDO/nwL6RZE2a9kO8q9CnJ6qQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/200Ag/btsFhVEhCDO/nwL6RZE2a9kO8q9CnJ6qQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F200Ag%2FbtsFhVEhCDO%2FnwL6RZE2a9kO8q9CnJ6qQ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;728&quot; height=&quot;456&quot; data-origin-width=&quot;728&quot; data-origin-height=&quot;456&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;localhost:4000으로 이동하면 이렇게 Operation을 작성하고 보낼 수 있는 창이 제공됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 아까 작성한 쿼리를 실행해 봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;828&quot; data-origin-height=&quot;440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zE930/btsFg5Hi29y/wG1Ye9nCAf1hYmvKYVKgbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zE930/btsFg5Hi29y/wG1Ye9nCAf1hYmvKYVKgbk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zE930/btsFg5Hi29y/wG1Ye9nCAf1hYmvKYVKgbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzE930%2FbtsFg5Hi29y%2FwG1Ye9nCAf1hYmvKYVKgbk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;828&quot; height=&quot;440&quot; data-origin-width=&quot;828&quot; data-origin-height=&quot;440&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 group 쿼리입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;존재하는 모든 Person들의 id, name, age를 받아오도록 하니 제대로 출력되는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;831&quot; data-origin-height=&quot;352&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkwW0g/btsFesKzltk/rUZKUvHl9fANodK52pcQM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkwW0g/btsFesKzltk/rUZKUvHl9fANodK52pcQM0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkwW0g/btsFesKzltk/rUZKUvHl9fANodK52pcQM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkwW0g%2FbtsFesKzltk%2FrUZKUvHl9fANodK52pcQM0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;831&quot; height=&quot;352&quot; data-origin-width=&quot;831&quot; data-origin-height=&quot;352&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;person 쿼리입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;person 쿼리부터는 인자가 필요하므로, name 값에 찾는 사람의 이름을 적어주면 위와 같이 해당 Person만 반환하는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;832&quot; data-origin-height=&quot;256&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/y4U4R/btsFfeE6cxL/A9RCkjFjpUMKGepLkWJ1P0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/y4U4R/btsFfeE6cxL/A9RCkjFjpUMKGepLkWJ1P0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/y4U4R/btsFfeE6cxL/A9RCkjFjpUMKGepLkWJ1P0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fy4U4R%2FbtsFfeE6cxL%2FA9RCkjFjpUMKGepLkWJ1P0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;832&quot; height=&quot;256&quot; data-origin-width=&quot;832&quot; data-origin-height=&quot;256&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 mutation들을 실행해 보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;mutation을 실행할 때에는 위와 같이 가장 바깥쪽의 중괄호 앞에 'mutation'이라고 명시해 주어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 createPerson입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;name과 age를 적어 create 해 주도록 하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반환값을 요청하지 않아도 자동으로 true를 반환하는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;835&quot; data-origin-height=&quot;463&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Y5GRv/btsFg1ZekHx/AN090TYG5utGRXdJFfbTJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Y5GRv/btsFg1ZekHx/AN090TYG5utGRXdJFfbTJk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Y5GRv/btsFg1ZekHx/AN090TYG5utGRXdJFfbTJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FY5GRv%2FbtsFg1ZekHx%2FAN090TYG5utGRXdJFfbTJk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;835&quot; height=&quot;463&quot; data-origin-width=&quot;835&quot; data-origin-height=&quot;463&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단히 Person들의 name만 요청해서 확인해 볼까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;zxcv&quot;라는 이름을 가진 Person이 group에 잘 추가된 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;837&quot; data-origin-height=&quot;207&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tk4qU/btsFf5HO3gy/LPSuqcGrJoPa7yJ9OGw4xk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tk4qU/btsFf5HO3gy/LPSuqcGrJoPa7yJ9OGw4xk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tk4qU/btsFf5HO3gy/LPSuqcGrJoPa7yJ9OGw4xk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ftk4qU%2FbtsFf5HO3gy%2FLPSuqcGrJoPa7yJ9OGw4xk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;837&quot; height=&quot;207&quot; data-origin-width=&quot;837&quot; data-origin-height=&quot;207&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 deletePerson입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;asdf&quot;라는 이름을 가진 Person을 group에서 제거해 보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;true 값이 정상적으로 반환되는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;824&quot; data-origin-height=&quot;375&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d1Dmgf/btsFgpF7i3Z/DDcPaXQX68Q77tUFyPtKbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d1Dmgf/btsFgpF7i3Z/DDcPaXQX68Q77tUFyPtKbk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d1Dmgf/btsFgpF7i3Z/DDcPaXQX68Q77tUFyPtKbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd1Dmgf%2FbtsFgpF7i3Z%2FDDcPaXQX68Q77tUFyPtKbk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;824&quot; height=&quot;375&quot; data-origin-width=&quot;824&quot; data-origin-height=&quot;375&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;group 쿼리로 확인해 보면, &quot;asdf&quot;라는 이름을 가진 Person이 성공적으로 제거된 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;What's next...&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 해서 간단한 쿼리와 뮤테이션들을 작성하고 실행해 보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이 코드의 경우에는 실제 DB가 아닌 코드의 배열에서 데이터를 다루고 있기 때문에 서버를 재시작하면 모든 변경 사항이 초기화되고 다시 &quot;asdf&quot;와 &quot;qwer&quot; 이름을 가진 Person들이 들어있는 group으로 시작할 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 우리는 별도로 상태를 저장할 데이터베이스가 필요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 시간에는 &lt;b&gt;Prisma Studio&lt;/b&gt;를 이용해 별도의 Database를 관리하는 방법에 대해 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>웹 개발/GraphQL</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/654</guid>
      <comments>https://restudycafe.tistory.com/654#entry654comment</comments>
      <pubDate>Sat, 24 Feb 2024 09:59:11 +0900</pubDate>
    </item>
    <item>
      <title>GraphQL typeDefs를 정의하고 Mutation resolvers로 조작하기</title>
      <link>https://restudycafe.tistory.com/653</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;GraphQL&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;GraphQL&lt;/b&gt;에는 &lt;span style=&quot;color: #ee2323;&quot;&gt;typeDefs&lt;/span&gt;와 &lt;span style=&quot;color: #ee2323;&quot;&gt;resolvers&lt;/span&gt;가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;typeDefs&lt;/b&gt;에는 우리가 사용할 데이터들의 자료형을 정의합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;resolvers&lt;/b&gt;에는 데이터를 변경하는 등 백엔드에 어떤 조치를 취할 때 작동할 함수를 정의합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 실제 서비스를 개발할 때는 분량이 매우 많아지므로, 각각의 typeDefs들과 resolvers들을 &lt;u&gt;개별적인 파일들로 분할하여 정리&lt;/u&gt;해 두는 것이 좋습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;typeDefs&lt;/b&gt;들은 다음과 같은 형식으로 작성합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1708692668255&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { gql } from &quot;apollo-server&quot;;

const typeDefs = gql`
    type User {
    	id: ID!
        username: String!
    }
    type Message {
    	id: ID!
        author: User!
        text: String!
    }
    type Query {
    	allMessages: [Messages!]!
        message(id: ID!): Message
    }
    type Mutation {
    	postMessage(text: String!, userId: ID!): Message!
    }
`;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GraphQL의 typeDefs에서 사용할 수 있는 데이터 타입으로는 ID, Int, String, Boolean, Float가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 주목할 점은 '&lt;b&gt;ID&lt;/b&gt;'라는 타입의 데이터가 있다는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ID는 &lt;u&gt;고유한 식별자&lt;/u&gt;로, 한 테이블에서 각 레코드가 유일한 ID 값을 가질 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기에서 type에 &lt;u&gt;느낌표( ! )를 붙이는 것&lt;/u&gt;은 값이 반드시 필요한 필드라는 뜻으로, &lt;b&gt;non-nullable type&lt;/b&gt;이라고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 non-nullable type 자료형에 값을 null로 두면 에러가 발생합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;resolver 작성을 위한 기초 JavaScript 문법 복습&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JavaScript에서 &lt;u&gt;배열의 길이&lt;/u&gt;는 다음과 같이 구합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1708692393845&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;변수명.length&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;배열에 새로운 값을 추가&lt;/u&gt;할 때는 다음과 같이 작성합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1708692407441&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;변수명.push(객체명)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주어진 &lt;u&gt;조건을 만족하는 배열의 첫 번째 요소&lt;/u&gt;를 구하기 위해서는 다음과 같이 작성합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1708692201293&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;변수명.find((element) =&amp;gt; { Boolean을 반환하는 함수 내용 })&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Mutation resolvers 작성 시 주의점&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;resolvers&lt;/b&gt;를 구현할 때 함수에서 받는 인자들은 &lt;span style=&quot;color: #ee2323;&quot;&gt;parent, args, context, info&lt;/span&gt; 순서입니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이중에서 &lt;b&gt;args&lt;/b&gt;는 &lt;u&gt;넘겨받은 인자들에 접근&lt;/u&gt;할 때 사용됩니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어서 message를 추가하는 mutation을 다음과 같이 작성할 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;context&lt;/b&gt;는 데이터베이스 연결이나 사용자 정보에 접근할 때 사용됩니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;info는 현재 쿼리에 대한 정보에 접근할 때 사용합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;** 단, &lt;u&gt;type resolvers에서는 첫 번째 인자가 object의 data&lt;/u&gt;입니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708692781702&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const resolvers = {
    Mutation: {
    	postMessage(_, { text, userId }) {
        	const newMessage = {
            	id: messages.length + 1,
                text,
            };
            messages.push(newMessage);
            return newMessage;
        }
    },
    User: {  // type resolvers
    	firstName({ firstName }) {  // type resolvers에서는 첫 번째 인자가 object data
        	return firstName;
        },
        fullName({ firstName, lastName }) {
        	return `${firstName} $lastName});
        },
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Mutation resolver를 작성할 때에는 mutation이&amp;nbsp;&lt;u&gt;제대로 처리되었는지 알 수 있도록 값을 반환&lt;/u&gt;해 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 예시 코드에서는 newMessage에 해당합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;GraphQL에서 Operation 작성하는 방법&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Operation(작업)은 클라이언트가 서버에 보내는 요청을 말합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;Query, Mutation, Subscription&lt;/span&gt; 3가지의 종류가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(이중에서 Subscription은 실시간 데이터 업데이트를 위한 작업입니다. 예를 들어서 실시간으로 메시지를 주고받는 채팅 등에서 활용될 수 있습니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, Mutation은 다음과 같이 작성할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708693007865&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mutation UpdateUser($userId: ID!, $name: String!) {
    updateUser(id: $userID, name: $name) {
    	id
        name
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기에다가 실제로 보내는 mutation과 같이 실제 변수를 넣으면 다음과 작성할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708693142647&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mutation UpdateUser($userId: ID!, $name: String!) {
    updateUser(id: &quot;1&quot;, name: &quot;codingterrace&quot;) {
    	id
        name
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또는 mutation은 그대로 두고, variables만 다음과 같이 따로 정의해서 mutation을 보낼 수도 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708693195630&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
    &quot;id&quot;: 1,
    &quot;name&quot;: codingterrace
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;작성한 Query와 Mutation 실행해 보기&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;879&quot; data-origin-height=&quot;371&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cujWwv/btsFgrYd9P8/U7i5Tk6haHd4IRtpjoko8k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cujWwv/btsFgrYd9P8/U7i5Tk6haHd4IRtpjoko8k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cujWwv/btsFgrYd9P8/U7i5Tk6haHd4IRtpjoko8k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcujWwv%2FbtsFgrYd9P8%2FU7i5Tk6haHd4IRtpjoko8k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;879&quot; height=&quot;371&quot; data-origin-width=&quot;879&quot; data-origin-height=&quot;371&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'&lt;u&gt;http://localhost:4000/&lt;/u&gt;'로 이동하면 GraphQL Query와 Mutation들을 직접 전송하고 응답을 확인해 볼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 이것은 로컬로 서버를 열었을 때의 상황이고, 외부에서 접속이 가능한 서버에서 열었을 때에는 알맞은 주소로 변경해주면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>웹 개발/GraphQL</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/653</guid>
      <comments>https://restudycafe.tistory.com/653#entry653comment</comments>
      <pubDate>Fri, 23 Feb 2024 21:38:42 +0900</pubDate>
    </item>
    <item>
      <title>React(리액트) create-react-app으로 프로젝트 생성하기</title>
      <link>https://restudycafe.tistory.com/652</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스트에서는 &lt;b&gt;create-react-app&lt;/b&gt;을 이용하여 리액트에서 프로젝트를 생성하고, &lt;u&gt;필요한 파일만 남기는 방법&lt;/u&gt;에 대해 다루어보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;create-react-app&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;create-react-app&lt;/b&gt;은 &lt;u&gt;리액트에서 제공하는 React 어플리케이션을 생성하기 위한 툴&lt;/u&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;npx 명령어를&amp;nbsp; 통해 create-react-app을 실행할 수 있는데, 이를 위해서는 &lt;b&gt;NodeJS&lt;/b&gt;가 설치되어 있어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 NodeJS가 설치되어 있지 않다면 공식 사이트로 가서 안정적인 버전의 NodeJS를 설치해주면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NodeJS를 설치하였다면 이제 터미널 등에서 프로젝트를 생성할 폴더로 이동하고, 다음의 명령어를 실행하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708346437581&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npx create-react-app (프로젝트 이름)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 (프로젝트 이름)이라는 이름으로 구성된 프로젝트 폴더가 생성됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;프로젝트 기본 구조 살펴보기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;폴더 안의 프로젝트 구조는 다음과 같은 형태를 가지고 있을 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;329&quot; data-origin-height=&quot;629&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cTx4eF/btsE6Qb8oAC/LBAKqteXcD8mD43gYLNHB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cTx4eF/btsE6Qb8oAC/LBAKqteXcD8mD43gYLNHB0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cTx4eF/btsE6Qb8oAC/LBAKqteXcD8mD43gYLNHB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcTx4eF%2FbtsE6Qb8oAC%2FLBAKqteXcD8mD43gYLNHB0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;329&quot; height=&quot;629&quot; data-origin-width=&quot;329&quot; data-origin-height=&quot;629&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 간단한 프로젝트를 만드는 데 대부분의 파일은 필요 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적인 것부터 살펴보기 위해서, 다음과 같이 필수적인 파일만 남겨둘 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;210&quot; data-origin-height=&quot;326&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbZXfB/btsEZQq98Ap/ey8CNYqtXYu4WdkzuK9j0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbZXfB/btsEZQq98Ap/ey8CNYqtXYu4WdkzuK9j0k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbZXfB/btsEZQq98Ap/ey8CNYqtXYu4WdkzuK9j0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbZXfB%2FbtsEZQq98Ap%2Fey8CNYqtXYu4WdkzuK9j0k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;210&quot; height=&quot;326&quot; data-origin-width=&quot;210&quot; data-origin-height=&quot;326&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;node_modules&lt;/b&gt;는 프로젝트에 필요한 모듈들을 저장하는 폴더이므로 삭제하면 안됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 프로젝트를 업로드할 때 node_modules에 있는 모듈들을 모두 업로드하지 않고, &lt;b&gt;package.json&lt;/b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;이라는 파일에 '이 프로젝트에 어떤 모듈들이 필요한지'에 대한 정보만을 저장&lt;/span&gt;하여 업로드할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 package.json 파일도 삭제하면 안됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;.gitignore&lt;/b&gt; 파일은 프로젝트를 업로드할 때 보안과 관련되거나 중요한 정보를 온라인 저장소에 노출시키지 않는 등 업로드하지 않아야 하는 파일의 목록을 관리하는 파일입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;필수적인 코드만 남기기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로&lt;b&gt; index.html&lt;/b&gt;은 다음과 같이 반드시 필요한 코드만 남깁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708347440990&quot; class=&quot;xml&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;en&quot;&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;utf-8&quot; /&amp;gt;
    &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot; /&amp;gt;
    &amp;lt;title&amp;gt;React App&amp;lt;/title&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;div id=&quot;root&quot;&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드에서 주의할 점은 body의 &lt;u&gt;id=&quot;root&quot;인 div&lt;/u&gt; 하나를 남겨야 한다는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;element가 하나라도 있어야 프로젝트에서 렌더링이 잘 작동하는지 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로 &lt;b&gt;index.js&lt;/b&gt;는 다음과 같이 매우 중요한 코드만 남깁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708347590974&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from &quot;react&quot;;
import ReactDOM from &quot;react-dom/client&quot;;
import App from &quot;./App&quot;;

const root = ReactDOM.createRoot(document.getElementById(&quot;root&quot;));
root.render(
  &amp;lt;React.StrictMode&amp;gt;
    &amp;lt;App /&amp;gt;
  &amp;lt;/React.StrictMode&amp;gt;
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &lt;span style=&quot;color: #ee2323;&quot;&gt;&amp;lt;React.StrictMode&amp;gt;&lt;/span&gt;는 React의 &lt;u&gt;개발 모드에서 검사를 엄격히&lt;/u&gt;하여 발생할 수 있는 문제들을 잡아내고 알려주는 역할을 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 반드시 필요한 것은 아니지만 여기서는 그냥 두도록 합시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 &lt;b&gt;App.js&lt;/b&gt;는 다음과 같이 작성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708347676015&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function App() {
  return &amp;lt;div&amp;gt;Hello&amp;lt;/div&amp;gt;;
}

export default App;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아까 html 태그로 남겨둔 &amp;lt;div id=&quot;root&amp;gt;에 Hello라는 텍스트를 작성해 봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 웹에서 어떻게 작동하는지 웹 화면을 확인해볼까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;프로젝트 실행해 보기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트의 실행을 위해서는 터미널에 &lt;span style=&quot;color: #ee2323;&quot;&gt;npm start&lt;/span&gt;를 입력해주면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 이와 관련된 명령어를 &lt;u&gt;package.json&lt;/u&gt; 파일에서 설정할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;npm start는 다음과 같이 프로젝트 생성 &lt;u&gt;처음부터 기본으로 작성되어 있는 명령어&lt;/u&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;349&quot; data-origin-height=&quot;144&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clBePB/btsE0jfD4aj/1lTDEsXZTmQnEx9gIvWwNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clBePB/btsE0jfD4aj/1lTDEsXZTmQnEx9gIvWwNk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clBePB/btsE0jfD4aj/1lTDEsXZTmQnEx9gIvWwNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FclBePB%2FbtsE0jfD4aj%2F1lTDEsXZTmQnEx9gIvWwNk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;349&quot; height=&quot;144&quot; data-origin-width=&quot;349&quot; data-origin-height=&quot;144&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;span style=&quot;color: #ee2323;&quot;&gt;npm start&lt;/span&gt;를 터미널에 쳐서 프로젝트가 제대로 작동하는지 확인해봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 결과는 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;345&quot; data-origin-height=&quot;199&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ds2I4p/btsEZz3441D/eTRqILddSOIku0m2hVJun0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ds2I4p/btsEZz3441D/eTRqILddSOIku0m2hVJun0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ds2I4p/btsEZz3441D/eTRqILddSOIku0m2hVJun0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fds2I4p%2FbtsEZz3441D%2FeTRqILddSOIku0m2hVJun0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;345&quot; height=&quot;199&quot; data-origin-width=&quot;345&quot; data-origin-height=&quot;199&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'&lt;span style=&quot;color: #ee2323;&quot;&gt;http://localhost:3000/&lt;/span&gt;'의 주소에 접속되며 프로젝트가 잘 작동하는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 3000은 React 프로젝트가 작동하는 포트의 번호로, 임의로 &lt;u&gt;빈 포트인 3000&lt;/u&gt;을 설정한 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 해서 create-react-app을 이용해 React의 프로젝트를 생성해 보고, 간단한 코드만 남겨 프로젝트가 제대로 작동하는지 확인해 볼 수 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>웹 개발/React</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/652</guid>
      <comments>https://restudycafe.tistory.com/652#entry652comment</comments>
      <pubDate>Mon, 19 Feb 2024 22:08:26 +0900</pubDate>
    </item>
    <item>
      <title>React(리액트) props(속성) 활용과 예시 (+ propTypes)</title>
      <link>https://restudycafe.tistory.com/651</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스트에서는 React(리액트)의 &lt;b&gt;props&lt;/b&gt;라는 기능에 대해 알아보고, 예시를 통해 &lt;u&gt;props가 어떻게 활용되는지&lt;/u&gt; 설명해보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Props(속성)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React(리액트)에서 props는 properties, 즉 속성이라는 뜻으로 &lt;span style=&quot;color: #ee2323;&quot;&gt;컴포넌트에 전달할 수 있는 데이터&lt;/span&gt;라는 뜻을 가지고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 변수와 같이 &lt;u&gt;컴포넌트에 유동적으로 변형을 주어야 할 때&lt;/u&gt;, props를 통해 값을 전달하여 &lt;u&gt;컴포넌트가 원하는 값을 나타낼 수 있도록 설정&lt;/u&gt;해 줄 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇듯 props를 활용하면 동일한 코드를 가지고도 여러 컴포넌트들의 &lt;b&gt;서로 다른 부분들만을 필요에 따라 다른 props 값을 전달&lt;/b&gt;하여 구현할 수 있으므로, &lt;span style=&quot;color: #ee2323;&quot;&gt;코드의 재사용성이 높아진다&lt;/span&gt;는 장점이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 5개의 디자인이 비슷한 서로 다른 버튼을 만들 때 5개의 컴포넌트 반환 함수를 구현할 필요없이, &lt;u&gt;1개의 컴포넌트 반환 함수만을 만들어 서로 다른 props 값을 받아 적용&lt;/u&gt;시키면 훨씬 코드가 간단해질 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게만 설명하면 이해하기 어려울 수 있으니 예시 코드를 통해 살펴봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실행 결과와 전체 코드&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;458&quot; data-origin-height=&quot;241&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JFr5R/btsEYXQJKZd/kWVxUk0ujDSaqEkbSMfFHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JFr5R/btsEYXQJKZd/kWVxUk0ujDSaqEkbSMfFHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JFr5R/btsEYXQJKZd/kWVxUk0ujDSaqEkbSMfFHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJFr5R%2FbtsEYXQJKZd%2FkWVxUk0ujDSaqEkbSMfFHK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;458&quot; height=&quot;241&quot; data-origin-width=&quot;458&quot; data-origin-height=&quot;241&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 개의 버튼이 있고, &lt;u&gt;두 버튼의 폰트 사이즈가 다른 것&lt;/u&gt;을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;darr; 전체 코드는 다음과 같습니다.&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1708184411056&quot; class=&quot;xml&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;&amp;lt;!-- index.html --&amp;gt;
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;div id=&quot;root&quot;&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;/body&amp;gt;
  &amp;lt;script src=&quot;https://unpkg.com/react@17.0.2/umd/react.production.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script src=&quot;https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script src=&quot;https://unpkg.com/@babel/standalone/babel.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script type=&quot;text/babel&quot;&amp;gt;
    function Btn(props) {
      return (
        &amp;lt;button
          style={{
            backgroundColor: &quot;#4CAF50&quot;,
            color: &quot;white&quot;,
            padding: &quot;10px 20px&quot;,
            border: 0,
            borderRadius: 10,
            cursor: &quot;pointer&quot;,
            marginRight: 10,
            fontSize: props.big ? 18 : 14,
          }}
        &amp;gt;
          {props.text}
        &amp;lt;/button&amp;gt;
      );
    }
    function App() {
      return (
        &amp;lt;div&amp;gt;
          &amp;lt;Btn text=&quot;왼쪽 버튼&quot; big={true} /&amp;gt;
          &amp;lt;Btn text=&quot;오른쪽 버튼&quot; big={false} /&amp;gt;
        &amp;lt;/div&amp;gt;
      );
    }
    ReactDOM.render(&amp;lt;App /&amp;gt;, root);
  &amp;lt;/script&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;코드 부분별로 살펴보기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 코드에서 중요한 부분을 살펴봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 Btn 컴포넌트를 생성하는 부분부터 자세히 살펴볼까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708183427044&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;Btn text=&quot;왼쪽 버튼&quot; big={true} /&amp;gt;
&amp;lt;Btn text=&quot;오른쪽 버튼&quot; big={false} /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2개의 Btn 컴포넌트를 생성하는데, &lt;u&gt;text라는 값과 big이라는 값을 설정&lt;/u&gt;해 주고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 'text'와 'big'이 리액트의 &lt;span style=&quot;color: #ee2323;&quot;&gt;Props&lt;/span&gt;에 해당합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2개의 값을 함수를 호출할 때 &lt;b&gt;인자를 전달하는 것처럼 값을 전달&lt;/b&gt;해 줄 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 Btn 함수에서 어떤 컴포넌트를 반환하는지 살펴볼까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708183660549&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Btn(props) {
  return (
    &amp;lt;button
      style={{
        fontSize: props.big ? 18 : 14,
      }}
    &amp;gt;
      {props.text}
    &amp;lt;/button&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CSS와 관련된 코드 중 필요없는 부분들은 거의 다 삭제하고, 필요한 부분만 남겨두었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보면 함수의 매개변수로 prop를 사용하며, &lt;b&gt;props.big&lt;/b&gt; 값과 &lt;b&gt;props.text&lt;/b&gt; 값을 자유롭게 사용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;fontSize와 같이 CSS 요소에도 사용할 수 있으며, 버튼에 들어갈 텍스트 부분에도 props의 값을 사용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 props.~와 같이 props의 하위 요소들로 접근하도록 코드를 매번 작성하면 불편할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 우리는 다음과 같이 속성 값을 바로 받아서 사용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;비구조화 할당(Destructuring)을 이용해 props 받아오기&lt;/h3&gt;
&lt;pre id=&quot;code_1708183792950&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Btn({ text, big }) {
  return (
    &amp;lt;button
      style={{
        fontSize: big ? 18 : 14,
      }}
    &amp;gt;
      {text}
    &amp;lt;/button&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 &lt;span style=&quot;color: #ee2323;&quot;&gt;중괄호를 이용하여 인자들을 받아주면&lt;/span&gt; 매번 'props.'라는 코드를 작성하지 않아도 되며, &lt;u&gt;정확히 어떤 값들이 함수의 인자로 전달되었는지 쉽게 확인&lt;/u&gt;할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;알 필요는 없지만, 이러한 방식을 '비구조화 할당(destructuring)을 이용해 props를 받아온다'라고 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;CSS 스타일 직접 지정하기&lt;/h3&gt;
&lt;pre id=&quot;code_1708183914036&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;Btn text=&quot;왼쪽 버튼&quot; fontSize={18} /&amp;gt;
&amp;lt;Btn text=&quot;오른쪽 버튼&quot; fontSize={14} /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 끝이 아니라, props로 &lt;u&gt;style의 속성값과 완전히 동일한 이름으로 인자를 전달&lt;/u&gt;하면, 다음과 같이 그 이름을 그대로 사용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, props를 이용하여 &lt;b&gt;CSS 스타일을 직접 지정&lt;/b&gt;해 줄 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708183942397&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  return (
    &amp;lt;button
      style={{
        fontSize,
      }}
    &amp;gt;
      {text}
    &amp;lt;/button&amp;gt;
  );&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;fontSize 부분이 보이시나요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 'fontSize: props의 변수명'과 같이 값을 대입해주지 않고 &lt;u&gt;바로 'fontSize'로 값을 사용&lt;/u&gt;할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 해서 지금까지 &lt;b&gt;props&lt;/b&gt;의 개념과 간단한 활용 방법에 대해 알아보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;+ propTypes에 대해 알아보기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;props에 대해 조금만 더 알아봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 &lt;b&gt;propTypes&lt;/b&gt;라는 기능에 대해 알아보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React의 propTypes란 &lt;span style=&quot;color: #ee2323;&quot;&gt;컴포넌트에 전달되는 props가 유효한지를 검사&lt;/span&gt;할 수 있는 기능입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단어의 뜻을 살펴보면 '속성의 타입'이라는 뜻을 가지고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 컴포넌트 생성 함수에 &lt;u&gt;제대로 된 타입의 데이터를 전달하고 있는지 체크&lt;/u&gt;할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;propTypes를 사용하기 위해서는 다음과 같이 script로 기능을 웹 링크에서 불러와주어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708220568450&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script src=&quot;https://unpkg.com/prop-types@15.7.2/prop-types.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 코드를 통해 &lt;b&gt;propTypes&lt;/b&gt;를 어떻게 지정할 수 있는지 살펴봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708220627771&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    function Btn({ text, fontSize }) {
      return (
        &amp;lt;button
          style={{
            fontSize,
          }}
        &amp;gt;
          {text}    
        &amp;lt;/button&amp;gt;
      );
    }
    Btn.propTypes = {
      text: PropTypes.string,
      fontSize: PropTypes.number,
    };&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 보았던 코드를 그대로 가져와서 propTypes를 작성하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'컴포넌트 이름.propTypes = { }'와 같이 작성해주고, 중괄호 안에는 &lt;u&gt;Object 형식으로 prop 속성명과 'PropTypes.데이터 타입'&lt;/u&gt;을 작성해주면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;여기서 주의할 점은, &lt;span style=&quot;color: #ee2323;&quot;&gt;객체명.propTypes의&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;맨 앞의 P는 소문자로, 내부의 속성은 대문자 P로 &lt;/span&gt;작성해 주어야 한다는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;반드시 필요한 값임을 명시하기 + 기본값 인자&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 어떤 prop 데이터가 반드시 필요한 값이라는 것을 명시해 줄 때에는 다음과 같이 작성해줄 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708222035637&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    Btn.propTypes = {
      text: PropTypes.string.isRequired,
      fontSize: PropTypes.number.isRequired,
    };&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 '&lt;b&gt;isRequired&lt;/b&gt;' 속성을 추가해주면 &lt;u&gt;해당 속성을 반드시 전달해 주어야 한다는 뜻&lt;/u&gt;이 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이럼에도 불구하고 JSX 요소 생성 시 값을 전달하지 않을 경우를 대비하여, &lt;b&gt;기본값 인자&lt;/b&gt;를 활용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본값 인자란 어떤 매개변수의 기본값을 지정함으로써 &lt;u&gt;해당 매개변수의 인자 값이 전달되지 않아도 자동으로 인자의 값을 설정&lt;/u&gt;하도록 하는 값을 말합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;406&quot; data-origin-height=&quot;432&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpJOQa/btsEV6H1Gjo/1Y2M17jFpzDHacruSkRKHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpJOQa/btsEV6H1Gjo/1Y2M17jFpzDHacruSkRKHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpJOQa/btsEV6H1Gjo/1Y2M17jFpzDHacruSkRKHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpJOQa%2FbtsEV6H1Gjo%2F1Y2M17jFpzDHacruSkRKHK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;406&quot; height=&quot;432&quot; data-origin-width=&quot;406&quot; data-origin-height=&quot;432&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 'fontSize = 14'와 같이 어떤 매개변수의 값을 지정해주면 해당 매개변수에 대응되는 &lt;u&gt;인자 값이 전달되지 않아도&lt;/u&gt; 자동으로 fontSize = 14로 설정해주게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 해서 리액트의 &lt;b&gt;prop&lt;/b&gt;의 개념과 활용법, 그리고 더 나아가 &lt;b&gt;propTypes&lt;/b&gt;라는 개념과 활용법에 대해서도 다뤄보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>웹 개발/React</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/651</guid>
      <comments>https://restudycafe.tistory.com/651#entry651comment</comments>
      <pubDate>Sun, 18 Feb 2024 00:39:03 +0900</pubDate>
    </item>
    <item>
      <title>React(리액트) 컴포넌트 분할/조각화를 통해 코드 가독성 높이기</title>
      <link>https://restudycafe.tistory.com/650</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이번 시간에는 React(리액트) 코드를 &lt;span style=&quot;color: #ee2323;&quot;&gt;여러 개의 JSX 요소들&lt;/span&gt;로 나누어 코드의 가독성을 높이는 방식으로 코드를 최적화해 보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실행 결과와 전체 코드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 실행 결과입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;kakaotv&quot; data-video-url=&quot;https://tv.kakao.com/v/444680244&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/bjCdTe/hyVjh6Xd0A/yCDWyOxmBEH6AAY50Yv2zk/img.jpg?width=456&amp;amp;height=376&amp;amp;face=0_0_456_376,https://scrap.kakaocdn.net/dn/R5K6k/hyVjidIK80/nZIAeUjsZSITcvAQk6xJmk/img.jpg?width=456&amp;amp;height=376&amp;amp;face=0_0_456_376&quot; data-video-width=&quot;456&quot; data-video-height=&quot;376&quot; data-video-origin-width=&quot;456&quot; data-video-origin-height=&quot;376&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-play-service=&quot;daum_tistory&quot; data-original-url=&quot;&quot; data-video-title=&quot;&quot;&gt;&lt;iframe src=&quot;https://play-tv.kakao.com/embed/player/cliplink/444680244?service=daum_tistory&quot; width=&quot;456&quot; height=&quot;376&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;select&lt;/b&gt; 태그를 사용하여 모드를 선택할 수 있고, &lt;u&gt;원하는 단위를 다른 단위로 변환&lt;/u&gt;할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;darr; 전체 코드는 다음과 같습니다.&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1708131728136&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!-- index.html --&amp;gt;
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;div id=&quot;root&quot;&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;/body&amp;gt;
  &amp;lt;script src=&quot;https://unpkg.com/react@17.0.2/umd/react.production.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script src=&quot;https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script src=&quot;https://unpkg.com/@babel/standalone/babel.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script type=&quot;text/babel&quot;&amp;gt;
    const MinutesToHours = () =&amp;gt; {
      const [amount, setAmount] = React.useState(0);
      const [inverted, setInverted] = React.useState(false);
      const onChange = (event) =&amp;gt; {
        setAmount(event.target.value);
      };
      const reset = () =&amp;gt; setAmount(0);
      const onFlip = () =&amp;gt; {
        reset();
        setInverted((current) =&amp;gt; !current);
      };
      return (
        &amp;lt;&amp;gt;
          &amp;lt;div&amp;gt;
            &amp;lt;input
              value={inverted ? Math.round(amount * 60 * 100) / 100 : amount}
              id=&quot;minutes&quot;
              placeholder=&quot;분&quot;
              type=&quot;number&quot;
              onChange={onChange}
              disabled={inverted}
              style={{ textAlign: &quot;right&quot; }}
            /&amp;gt;
            &amp;lt;label htmlFor=&quot;minutes&quot;&amp;gt; 분&amp;lt;/label&amp;gt;
          &amp;lt;/div&amp;gt;
          &amp;lt;div&amp;gt;
            &amp;lt;input
              value={inverted ? amount : Math.round((amount / 60) * 100) / 100}
              id=&quot;hours&quot;
              placeholder=&quot;시간&quot;
              type=&quot;number&quot;
              disabled={!inverted}
              onChange={onChange}
              style={{ textAlign: &quot;right&quot; }}
            /&amp;gt;
            &amp;lt;label htmlFor=&quot;hours&quot;&amp;gt; 시간&amp;lt;/label&amp;gt;
          &amp;lt;/div&amp;gt;
          &amp;lt;button onClick={reset}&amp;gt;초기화&amp;lt;/button&amp;gt;
          &amp;lt;button onClick={onFlip}&amp;gt;뒤집기&amp;lt;/button&amp;gt;
        &amp;lt;/&amp;gt;
      );
    };
    const KilometersToMiles = () =&amp;gt; {
      const [amount, setAmount] = React.useState(0);
      const [inverted, setInverted] = React.useState(false);
      const onChange = (event) =&amp;gt; {
        setAmount(event.target.value);
      };
      const reset = () =&amp;gt; setAmount(0);
      const onFlip = () =&amp;gt; {
        reset();
        setInverted((current) =&amp;gt; !current);
      };
      return (
        &amp;lt;&amp;gt;
          &amp;lt;div&amp;gt;
            &amp;lt;input
              value={inverted ? Math.round(amount * 1.609 * 100) / 100 : amount}
              id=&quot;kilometers&quot;
              placeholder=&quot;킬로미터&quot;
              type=&quot;number&quot;
              onChange={onChange}
              disabled={inverted}
              style={{ textAlign: &quot;right&quot; }}
            /&amp;gt;
            &amp;lt;label htmlFor=&quot;minutes&quot;&amp;gt; 킬로미터&amp;lt;/label&amp;gt;
          &amp;lt;/div&amp;gt;
          &amp;lt;div&amp;gt;
            &amp;lt;input
              value={
                inverted ? amount : Math.round((amount / 1.609) * 100) / 100
              }
              id=&quot;miles&quot;
              placeholder=&quot;마일&quot;
              type=&quot;number&quot;
              disabled={!inverted}
              onChange={onChange}
              style={{ textAlign: &quot;right&quot; }}
            /&amp;gt;
            &amp;lt;label htmlFor=&quot;hours&quot;&amp;gt; 마일&amp;lt;/label&amp;gt;
          &amp;lt;/div&amp;gt;
          &amp;lt;button onClick={reset}&amp;gt;초기화&amp;lt;/button&amp;gt;
          &amp;lt;button onClick={onFlip}&amp;gt;뒤집기&amp;lt;/button&amp;gt;
        &amp;lt;/&amp;gt;
      );
    };
    function App() {
      const [index, setIndex] = React.useState(&quot;x&quot;);
      const onSelect = (event) =&amp;gt; {
        setIndex(event.target.value);
      };
      return (
        &amp;lt;div&amp;gt;
          &amp;lt;h1&amp;gt;단위 변환기&amp;lt;/h1&amp;gt;
          &amp;lt;select value={index} onChange={onSelect}&amp;gt;
            &amp;lt;option value=&quot;x&quot;&amp;gt;단위를 선택해주세요.&amp;lt;/option&amp;gt;
            &amp;lt;option value=&quot;0&quot;&amp;gt;시간 &amp;harr; 분&amp;lt;/option&amp;gt;
            &amp;lt;option value=&quot;1&quot;&amp;gt;킬로미터 &amp;harr; 마일&amp;lt;/option&amp;gt;
          &amp;lt;/select&amp;gt;
          &amp;lt;hr /&amp;gt;
          {index === &quot;x&quot; ? &quot;단위를 선택해주세요.&quot; : null}
          {index === &quot;0&quot; ? &amp;lt;MinutesToHours /&amp;gt; : null}
          {index === &quot;1&quot; ? &amp;lt;KilometersToMiles /&amp;gt; : null}
        &amp;lt;/div&amp;gt;
      );
    }
    const root = document.getElementById(&quot;root&quot;);
    ReactDOM.render(&amp;lt;App /&amp;gt;, root);
  &amp;lt;/script&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;코드 부분별로 살펴보기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이제 코드를 &lt;u&gt;여러 개의 작은 JSX 요소로 나누는 것&lt;/u&gt;이 어떤 장점이 있는지 살펴봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708131769971&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;div&amp;gt;
  &amp;lt;h1&amp;gt;단위 변환기&amp;lt;/h1&amp;gt;
  &amp;lt;select value={index} onChange={onSelect}&amp;gt;
    &amp;lt;option value=&quot;x&quot;&amp;gt;단위를 선택해주세요.&amp;lt;/option&amp;gt;
    &amp;lt;option value=&quot;0&quot;&amp;gt;시간 &amp;harr; 분&amp;lt;/option&amp;gt;
    &amp;lt;option value=&quot;1&quot;&amp;gt;킬로미터 &amp;harr; 마일&amp;lt;/option&amp;gt;
  &amp;lt;/select&amp;gt;
  &amp;lt;hr /&amp;gt;
  {index === &quot;x&quot; ? &quot;단위를 선택해주세요.&quot; : null}
  {index === &quot;0&quot; ? &amp;lt;MinutesToHours /&amp;gt; : null}
  {index === &quot;1&quot; ? &amp;lt;KilometersToMiles /&amp;gt; : null}
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주목할 코드는 이 부분입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;select&lt;/b&gt; 태그를 이용하면 &lt;u&gt;정해진 목록들 중 하나를 선택&lt;/u&gt;할 수 있게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 만약 &lt;span style=&quot;color: #ee2323;&quot;&gt;option을 변경한다면, onChange라는 이벤트를 발생&lt;/span&gt;시킬 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React에서 자동으로 onChange 이벤트가 감지되면, 우리는 그때 &lt;u&gt;실행할 함수를 지정&lt;/u&gt;해줄 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708131889236&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const [index, setIndex] = React.useState(&quot;x&quot;);
const onSelect = (event) =&amp;gt; {
  setIndex(event.target.value);
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드를 살펴볼까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 위에서 사용자가 option을 변경했을 때 onSelect라는 함수를 실행하도록 지정해두었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 &lt;b&gt;onSelect 함수&lt;/b&gt;에서는 우리가 이전에 배운 State 개념을 활용하여 &lt;u&gt;변수의 값을 실시간으로 바꿔줄 수 있습니다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 setIndex 함수를 호출하여 event에서 선택한 value 값으로 index 값을 변경해 줄 수 있겠네요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708131997692&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{index === &quot;x&quot; ? &quot;단위를 선택해주세요.&quot; : null}
{index === &quot;0&quot; ? &amp;lt;MinutesToHours /&amp;gt; : null}
{index === &quot;1&quot; ? &amp;lt;KilometersToMiles /&amp;gt; : null}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방금 살펴보았던 코드입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;index 값이 setIndex 함수에 의해 변경됨에 따라, 위와 같은 삼항 연산자를 활용하여 &lt;u&gt;각 코드 블록이 실행되거나 실행되지 않도록 할 수 있습니다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기에서 &lt;span style=&quot;color: #ee2323;&quot;&gt;JSX 요소&lt;/span&gt;가 굉장히 유용하게 쓰입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드의 위에서는 'const MinutesToHours = () =&amp;gt; {}'와 같이 MinutesToHours가 호출되었을 때 실행할 코드가 작성되어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 긴 코드를 삼항연산자에 길게 작성할 필요 없이, &lt;span style=&quot;color: #ee2323;&quot;&gt;위에서 작성한 JSX 요소의 이름만을 태그로 달아 해당 코드가 실행될 수 있도록 하는 것&lt;/span&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 &lt;b&gt;코드를 조각화&lt;/b&gt;하여 활용해 주면 &lt;u&gt;코드의 가독성을 높이고 이해하기 쉬운 코드를 작성&lt;/u&gt;할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;419&quot; data-origin-height=&quot;321&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfA4A3/btsEZaoDfkp/exVAojuupMZp41AhEtw3w0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfA4A3/btsEZaoDfkp/exVAojuupMZp41AhEtw3w0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfA4A3/btsEZaoDfkp/exVAojuupMZp41AhEtw3w0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfA4A3%2FbtsEZaoDfkp%2FexVAojuupMZp41AhEtw3w0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;419&quot; height=&quot;321&quot; data-origin-width=&quot;419&quot; data-origin-height=&quot;321&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 해서 간단한 단위 변환기에 여러 가지 모드를 추가하고, 삼항 연산자와 JSX 요소들을 이용하여 코드를 분할 및 조각화를 하고 코드의 가독성을 높이는 방법을 살펴보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>웹 개발/React</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/650</guid>
      <comments>https://restudycafe.tistory.com/650#entry650comment</comments>
      <pubDate>Sat, 17 Feb 2024 10:10:26 +0900</pubDate>
    </item>
    <item>
      <title>React(리액트) State를 이용해 단위 변환기 구현하기</title>
      <link>https://restudycafe.tistory.com/649</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이번 시간에는 React(리액트)의 &lt;b&gt;State&lt;/b&gt;를 이용해 단위 변환기를 구현해보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리액트에서 State는 이름 그대로 '&lt;u&gt;컴포넌트의 상태&lt;/u&gt;', 또는 '&lt;u&gt;컴포넌트 안에서 관리되는 데이터&lt;/u&gt;'를 의미합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;State를 이용해 어떤 컴포넌트의 상태를 변경하면, &lt;span style=&quot;color: #ee2323;&quot;&gt;React는 자동으로 이 컴포넌트만을 다시 렌더링하여 변경된 상태를 페이지에 반영&lt;/span&gt;해줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React의 State를 사용하는 것이 좋은 이유는, 리액트는 앞서 말한대로 &lt;b&gt;필요한 부분만 다시 렌더링&lt;/b&gt;하므로, 값이 바뀐다고 페이지 전체를 다시 렌더링할 필요가 없기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 매우 효율적으로, &lt;b&gt;화면에 변화가 필요한 부분만을 다시 로딩&lt;/b&gt;할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 Vanilla Javascript에서도 수동적으로 DOM을 조작할 수 있지만, 매우 긴 코드가 필요하고 따라서 번거롭습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 리액트의 State를 사용한다면 &lt;b&gt;리액트가 자동으로 변경 사항을 감지하고 UI를 업데이트&lt;/b&gt;해 줄 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;453&quot; data-origin-height=&quot;284&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqzStD/btsEWyxfdZ9/C3PSUdTA3CYmottfwXLbW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqzStD/btsEWyxfdZ9/C3PSUdTA3CYmottfwXLbW1/img.png&quot; data-alt=&quot;index.html 실행 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqzStD/btsEWyxfdZ9/C3PSUdTA3CYmottfwXLbW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqzStD%2FbtsEWyxfdZ9%2FC3PSUdTA3CYmottfwXLbW1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;453&quot; height=&quot;284&quot; data-origin-width=&quot;453&quot; data-origin-height=&quot;284&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;index.html 실행 결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 언급한대로 이 포스트에서는 위와 같은 '시간 &amp;harr; 분 변환기'를 구현해볼 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;index.html의 코드는 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708092496544&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!-- index.html --&amp;gt;
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;div id=&quot;root&quot;&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;/body&amp;gt;
  &amp;lt;script src=&quot;https://unpkg.com/react@17.0.2/umd/react.production.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script src=&quot;https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script src=&quot;https://unpkg.com/@babel/standalone/babel.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script type=&quot;text/babel&quot;&amp;gt;
    function App() {
      const [amount, setAmount] = React.useState(0);
      const [inverted, setInverted] = React.useState(false);
      const onChange = (event) =&amp;gt; {
        setAmount(event.target.value);
      };
      const reset = () =&amp;gt; setAmount(0);
      const onFlip = () =&amp;gt; {
        reset();
        setInverted((current) =&amp;gt; !current);
      };
      return (
        &amp;lt;div&amp;gt;
          &amp;lt;h1&amp;gt;시간 &amp;harr; 분 변환기&amp;lt;/h1&amp;gt;
          &amp;lt;div&amp;gt;
            &amp;lt;input
              value={inverted ? Math.round(amount * 60 * 100) / 100 : amount}
              id=&quot;minutes&quot;
              placeholder=&quot;분&quot;
              type=&quot;number&quot;
              onChange={onChange}
              disabled={inverted}
              style={{ textAlign: &quot;right&quot; }}
            /&amp;gt;
            &amp;lt;label htmlFor=&quot;minutes&quot;&amp;gt; 분&amp;lt;/label&amp;gt;
          &amp;lt;/div&amp;gt;
          &amp;lt;div&amp;gt;
            &amp;lt;input
              value={inverted ? amount : Math.round((amount / 60) * 100) / 100}
              id=&quot;hours&quot;
              placeholder=&quot;시간&quot;
              type=&quot;number&quot;
              disabled={!inverted}
              onChange={onChange}
              style={{ textAlign: &quot;right&quot; }}
            /&amp;gt;
            &amp;lt;label htmlFor=&quot;hours&quot;&amp;gt; 시간&amp;lt;/label&amp;gt;
          &amp;lt;/div&amp;gt;
          &amp;lt;button onClick={reset}&amp;gt;초기화&amp;lt;/button&amp;gt;
          &amp;lt;button onClick={onFlip}&amp;gt;뒤집기&amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;gt;
      );
    }
    const root = document.getElementById(&quot;root&quot;);
    ReactDOM.render(&amp;lt;App /&amp;gt;, root);
  &amp;lt;/script&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주목해서 볼만한 부분을 자세히 살펴보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708093303040&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const [amount, setAmount] = React.useState(0);
const [inverted, setInverted] = React.useState(false);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 여기서는 &lt;b&gt;amount&lt;/b&gt;와 &lt;b&gt;inverted&lt;/b&gt;라는 &lt;span style=&quot;color: #ee2323;&quot;&gt;state&lt;/span&gt;를 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;amount는 input 태그에 입력된 값을 나타내고, inverted는 false면 위 칸이 활성화, true면 아래 칸이 활성화되도록 할 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;useState&lt;/span&gt;는 &lt;u&gt;리액트에 내장되어있는 훅(Hook)&lt;/u&gt;의 한 종류입니다. (여기서 훅은 컴포넌트의 상태나 생명주기 등을 관리할 수 있도록 도와주는 기능을 뜻합니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;useState()&lt;/b&gt; 함수는 두 개의 값을 반환하는데, 첫 번째 값은 &lt;span style=&quot;color: #ee2323;&quot;&gt;상태&lt;/span&gt;, 두 번째 값은 &lt;span style=&quot;color: #ee2323;&quot;&gt;해당 상태를 업데이트할 수 있는 함수&lt;/span&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 우리는 &lt;b&gt;[value, setValue]&lt;/b&gt;와 같이 &lt;u&gt;상태와 업데이트 함수를 각각 받아올 수 있습니다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;useState 함수의 인자로는 상태의 초깃값을 지정&lt;/u&gt;해주면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708093695708&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;input
  value={inverted ? Math.round(amount * 60 * 100) / 100 : amount}
  id=&quot;minutes&quot;
  type=&quot;number&quot;
  onChange={onChange}
  disabled={inverted}
/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 번째 input 태그만 살펴봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 inverted가 true인 경우 아래 칸의 입력에 따라 현재 칸의 값을 설정할 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 칸은 단위가 시간이고, 아래 칸은 단위가 분이므로, amount(시간)을 (분)으로 변환하기 위해 60을 곱해주면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 inverted가 false인 경우는 현재 칸이 활성화된 것이므로 입력한 값 그대로 value로 설정해주면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;b&gt;onChange&lt;/b&gt; 이벤트를 살펴봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 이벤트는 &lt;span style=&quot;color: #ee2323;&quot;&gt;사용자가 입력 필드의 값을 바꿀 때마다 발생&lt;/span&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 이 경우 실행할 함수를 정의해두고 적어주면, 값이 바뀔 때마다 호출이 될 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서는 onChange() 함수를 사용할 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 onChange() 함수를 살펴볼까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708093946111&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const onChange = (event) =&amp;gt; {
  setAmount(event.target.value);
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;onChange() 함수의 구현은 이 포스트에 한해서는 별 내용이 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐하면 그냥 변화된 값을 그대로 input 내용으로 반영해주기만 하면 되기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발생한 이벤트 객체를 &lt;b&gt;event&lt;/b&gt;라고 했을 때, &lt;span style=&quot;color: #ee2323;&quot;&gt;event.target.value&lt;/span&gt;와 같이 접근하면 &lt;u&gt;입력 필드에 입력된 값에 접근&lt;/u&gt;할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 값을 &lt;b&gt;setAmount&lt;/b&gt;를 이용해 업데이트해주면, 리액트가 실시간으로 해당 컴포넌트를 업데이트 해줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 두 번째 input 태그도 비슷한 원리로 작성해주면, 단위 변환기를 성공적으로 구현할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;420&quot; data-origin-height=&quot;307&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/daxJJt/btsEWiH6O6n/6h9KDKkU0Gm4w5SXt75p9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/daxJJt/btsEWiH6O6n/6h9KDKkU0Gm4w5SXt75p9K/img.png&quot; data-alt=&quot;뒤집기를 눌러 invert 시킨 후 값을 입력한 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/daxJJt/btsEWiH6O6n/6h9KDKkU0Gm4w5SXt75p9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdaxJJt%2FbtsEWiH6O6n%2F6h9KDKkU0Gm4w5SXt75p9K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;420&quot; height=&quot;307&quot; data-origin-width=&quot;420&quot; data-origin-height=&quot;307&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;뒤집기를 눌러 invert 시킨 후 값을 입력한 결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 뒤집기 버튼을 누른 후 시간 값을 입력해도 분 단위로 잘 변화가 일어나는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>웹 개발/React</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/649</guid>
      <comments>https://restudycafe.tistory.com/649#entry649comment</comments>
      <pubDate>Fri, 16 Feb 2024 23:37:40 +0900</pubDate>
    </item>
    <item>
      <title>React(리액트) 컴포넌트와 이벤트 간단하게 만들고 렌더링하기</title>
      <link>https://restudycafe.tistory.com/648</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;React(리액트)를 이용해 간단한 컴포넌트와 이벤트를 간단하게 구현해봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;컴포넌트와 이벤트 구현&lt;/h4&gt;
&lt;pre id=&quot;code_1707748725189&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!-- index.html --&amp;gt;
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;div id=&quot;root&quot;&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;/body&amp;gt;
  &amp;lt;script src=&quot;https://unpkg.com/react@17.0.2/umd/react.production.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script src=&quot;https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script src=&quot;https://unpkg.com/@babel/standalone/babel.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script type=&quot;text/babel&quot;&amp;gt;
    const root = document.getElementById(&quot;root&quot;);
    const Title = (
      &amp;lt;h3 id=&quot;title&quot; onMouseEnter={() =&amp;gt; console.log(&quot;마우스가 들어왔습니다.&quot;)}&amp;gt;
        h3 텍스트
      &amp;lt;/h3&amp;gt;
    );
    const Button = (
      &amp;lt;button
        style={{ backgroundColor: &quot;gray&quot; }}
        onClick={() =&amp;gt; console.log(&quot;클릭되었습니다.&quot;)}
      &amp;gt;
        클릭해보세요!
      &amp;lt;/button&amp;gt;
    );
    const container = React.createElement(&quot;div&quot;, null, [Title, Button]);
    ReactDOM.render(container, root);
  &amp;lt;/script&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;949&quot; data-origin-height=&quot;526&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qIP5w/btsENSA0yTR/zqhVAiKDJjIlqjlkWnrpkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qIP5w/btsENSA0yTR/zqhVAiKDJjIlqjlkWnrpkk/img.png&quot; data-alt=&quot;index.html 실행 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qIP5w/btsENSA0yTR/zqhVAiKDJjIlqjlkWnrpkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqIP5w%2FbtsENSA0yTR%2FzqhVAiKDJjIlqjlkWnrpkk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;949&quot; height=&quot;526&quot; data-origin-width=&quot;949&quot; data-origin-height=&quot;526&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;index.html 실행 결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;h3 텍스트에 마우스가 진입하면 '마우스가 들어왔습니다.'라는 텍스트가 콘솔에 출력되고, 버튼을 클릭하면 '클릭되었습니다.'라는 문구가 콘솔에 출력됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드가 어떻게 작동하는지 한 줄씩 확인해봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1707748954872&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script src=&quot;https://unpkg.com/react@17.0.2/umd/react.production.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드는 사용자 인터페이스를 만들기 위한 JavaScript 라이브러리 중 하나인 &lt;u&gt;React를 로드&lt;/u&gt;하는 코드입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1707749008349&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script src=&quot;https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드는 React에서 작성한 &lt;u&gt;객체 모델인 DOM을 실제 페이지에 표시하는 역할&lt;/u&gt;을 수행하는, ReactDOM을 로드하는 코드입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1707749089700&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script src=&quot;https://unpkg.com/@babel/standalone/babel.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드는 &lt;u&gt;최신 버전의 JavaScript 코드를 옛날 버전의 JavaScript 코드로 변환해주는 역할&lt;/u&gt;을 수행하는, &lt;b&gt;Babel&lt;/b&gt;을 로드하는 코드입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필요한 기능들을 모두 로드했으니 이제 React에서 컴포넌트를 생성하는 방법에 대해 알아봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1707749214891&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const Title = (
  &amp;lt;h3 id=&quot;title&quot; onMouseEnter={() =&amp;gt; console.log(&quot;마우스가 들어왔습니다.&quot;)}&amp;gt;
    h3 텍스트
  &amp;lt;/h3&amp;gt;
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JavaScript의 확장 문법인 &lt;b&gt;JSX 문법&lt;/b&gt;을 사용하면 &lt;u&gt;컴포넌트를 이렇게 HTML 문법에 가깝게 작성하여 생성하고, 해당 컴포넌트에 이벤트를 추가&lt;/u&gt;할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 이 &lt;u&gt;문법을 옛날 JavaScript 코드처럼 인식시키기 위해서, 위에서 로드한 Babel이 필요&lt;/u&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 Vanilla JavaScript 문법과 비교했을 때 훨씬 간단하게 컴포넌트를 생성하고 이벤트를 추가할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1707749327722&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const root = document.getElementById(&quot;root&quot;);
const container = React.createElement(&quot;div&quot;, null, [Title, Button]);
ReactDOM.render(container, root);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 root 요소를 찾아주고, 컨테이너를 구성한 뒤 root에 container를 렌더해주면 첫 이미지로 첨부한 화면과 같이 컴포넌트와 이벤트가 제대로 렌더되는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;코드 개선&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 확인해보면 Container는 Title 컴포넌트와 Button 컴포넌트를 포함하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리액트(React)에서는 이 &lt;span style=&quot;color: #ee2323;&quot;&gt;컴포넌트들을 html 형식의 문법으로 작성&lt;/span&gt;해 줄 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1707922235039&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!-- index.html --&amp;gt;
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;div id=&quot;root&quot;&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;/body&amp;gt;
  &amp;lt;script src=&quot;https://unpkg.com/react@17.0.2/umd/react.production.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script src=&quot;https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script src=&quot;https://unpkg.com/@babel/standalone/babel.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script type=&quot;text/babel&quot;&amp;gt;
    const root = document.getElementById(&quot;root&quot;);
    const Title = () =&amp;gt; (
      &amp;lt;h3 id=&quot;title&quot; onMouseEnter={() =&amp;gt; console.log(&quot;마우스가 들어왔습니다.&quot;)}&amp;gt;
        h3 텍스트
      &amp;lt;/h3&amp;gt;
    );
    const Button = () =&amp;gt; (
      &amp;lt;button
        style={{ backgroundColor: &quot;gray&quot; }}
        onClick={() =&amp;gt; console.log(&quot;클릭되었습니다.&quot;)}
      &amp;gt;
        클릭해보세요!
      &amp;lt;/button&amp;gt;
    );
    const Container = (
      &amp;lt;div&amp;gt;
        &amp;lt;Title /&amp;gt;
        &amp;lt;Button /&amp;gt;
      &amp;lt;/div&amp;gt;
    );
    ReactDOM.render(Container, root);
  &amp;lt;/script&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 &lt;u&gt;h3 컴포넌트로 구현해준 Title을, h3 &lt;span style=&quot;color: #ee2323;&quot;&gt;컴포넌트를 반환하는 함수&lt;/span&gt;로 바꿔줍니다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 우리는 &lt;b&gt;&amp;lt;Title /&amp;gt;&lt;/b&gt;과 같이 호출하여 작성한 위치에서 우리가 선언한 컴포넌트를 반환받을 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 주의할 점은, 함수 이름의 첫 글자를 반드시 대문자로 작성해주어야 한다는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수 이름의 첫 글자를 소문자로 작성한다면, 해당 코드 조각을 호출할 때 태그 이름을 html 태그로 인식하게 되기 때문입니다. (이를 구분하기 위해 대문자로 작성하도록 설정되어 있습니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Button에 대해서도 동일한 처리를 해줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 코드를 작성하면, &lt;u&gt;html 형식과 거의 비슷하게 작성하면서도&lt;/u&gt; &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;코드 조각들을&lt;span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt; 한눈에 알아보기 쉽게&lt;/span&gt; 배치할 수 있게 됩니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>웹 개발/React</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/648</guid>
      <comments>https://restudycafe.tistory.com/648#entry648comment</comments>
      <pubDate>Mon, 12 Feb 2024 23:50:02 +0900</pubDate>
    </item>
    <item>
      <title>Codeforces 퍼플 달성 / 2022 BOJ solved 1위 / 블로그 접습니다 (+ 수정 : 다시 시작합니다!)</title>
      <link>https://restudycafe.tistory.com/645</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;Codeforces 퍼플 달성&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;864&quot; data-origin-height=&quot;472&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Dstva/btrU55SwlTM/cRcbYhGVdSgOq3V6kN73W1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Dstva/btrU55SwlTM/cRcbYhGVdSgOq3V6kN73W1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Dstva/btrU55SwlTM/cRcbYhGVdSgOq3V6kN73W1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDstva%2FbtrU55SwlTM%2FcRcbYhGVdSgOq3V6kN73W1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;767&quot; height=&quot;419&quot; data-origin-width=&quot;864&quot; data-origin-height=&quot;472&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드포스의 Goodbye 2022 대회에서 적당한 레이팅을 띄웠고 덕분에 2022년이 끝나기 전에 &lt;b&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;퍼플&lt;/span&gt;&lt;/b&gt;을 달성할 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나처럼 어려운 문제 푸는거 싫어하고 업솔빙이 재미없다면 그냥 컨테스트만 꾸준히 쳐도 경험이 쌓이니 이를 추천한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;9개월 정도 걸렸는데 재능 있는 사람들이 훨씬 빨리 올라가는거 보면 부럽긴 하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;BOJ 2022 solved 수 1위&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1204&quot; data-origin-height=&quot;474&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Q4jTb/btrU1qwtA39/fXzBRAN1lZImChKSHPoGRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Q4jTb/btrU1qwtA39/fXzBRAN1lZImChKSHPoGRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Q4jTb/btrU1qwtA39/fXzBRAN1lZImChKSHPoGRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQ4jTb%2FbtrU1qwtA39%2FfXzBRAN1lZImChKSHPoGRk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1204&quot; height=&quot;474&quot; data-origin-width=&quot;1204&quot; data-origin-height=&quot;474&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백준에서 1년동안 문제를 제일 많이 푼 등수인데 보니까 올해는 내가 1등을 기록했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;심심할 때마다 풀었는데 어려운 거 고민하기는 싫어서 브론즈 실버 난이도 문제들을 거의 다 풀다시피 풀었더니 이렇게 된 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무튼 푼 문제 수는 실력이랑은 큰 관계 없다는 거&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;추후 계획&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이 글을 누가 볼지는 모르겠지만 블로그는 접으려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞으로 크게 바빠져서 알고리즘을 공부할 시간이 없을 것 같기도 하고, 공부할 내용을 여기에 정리할만큼 시간이 많지도 않을 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 필요하다면 가끔씩 공부 관련 글들이 몇 개 더 올라올 수는 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;광고는 모두 내렸고, 필요없는 글들도 정리했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 혹시나 검색 유입으로 정보를 얻어가시는 분들이 계실까봐 공부 관련 글들은 남겨두었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국은 혼자 보려고 정리하기 시작한 내용들이지만 누군가에게 도움이 되기를 바란다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;다시 시작! (2024 ~)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발 공부와 관련한 내용들을 정리하기 위해 포스트 작성을 다시 시작합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에도 역시 공부한 내용들을 혼자 정리하고 나중에 잊어버렸을 때 스스로 빠르게 참고하고 다시 활용하기 위해 포스트를 작성하지만, 혹시라도 보시는 분들이 계시다면 도움이 되셨으면 좋겠습니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>근황 + 공지사항</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/645</guid>
      <comments>https://restudycafe.tistory.com/645#entry645comment</comments>
      <pubDate>Sat, 31 Dec 2022 18:35:27 +0900</pubDate>
    </item>
    <item>
      <title>12월 알고리즘 공부 : 퍼시스턴트 세그먼트 트리, 머지 소트 트리, 오일러 회로 등</title>
      <link>https://restudycafe.tistory.com/644</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 11012번 : Egg&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;퍼시스턴트 세그먼트 트리&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2차원 좌표계에서 점들의 좌표가 주어질 때, 직사각형 영역이 쿼리로 주어지면 해당 영역에 점이 몇 개가 있는지를 구하는 문제이다. (0 &amp;le; x, y &amp;le; 10^5, Q &amp;le; 50,000)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1차원 좌표계였다면 일반적인 세그먼트 트리로 해결이 가능한 것은 물론이고 값의 갱신이 없으므로 누적 합으로도 쉽게 계산이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2차원 좌표계 + 작은 범위였다면 2차원 배열의 누적 합으로 쉽게 계산이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제에서는 세그먼트 트리 또는 2차원 배열을 선언하면 메모리 초과가 발생하게 되는데 이를 어떻게 해결할 수 있을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 문제는 &lt;b&gt;퍼시스턴트 세그먼트 트리(Persistent Segment Tree, PST)&lt;/b&gt;로 풀이할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;퍼시스턴트 세그먼트 트리&lt;/b&gt;는 노드의 갱신 기록을 저장하고 있는 트리이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;예를 들어 0번 트리에서 어떤 노드가 갱신되면, 1번 트리를 만들고 갱신되는 노드들만 1번 트리에 노드를 만들고 0번 트리와 연결시킨다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;이런 식으로 해나가면 하나의 새로운 트리에 log N개 정도의 노드만 새로 갱신하면 되므로, M개의 갱신에 대해서도 M log N개의 노드만 저장하면 되므로 메모리를 효율적으로 아낄 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대신 구현이 조금 더 복잡한데, 아래의 코드를 참고하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제에서는 x값에 하나의 트리가 대응되게 하였으며, 각 &lt;span style=&quot;color: #ee2323;&quot;&gt;x값에 해당하는 y값들을 x번 트리의 y번 노드에 대응&lt;/span&gt;되도록 하여 데이터를 저장하게 구현하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후는 누적 합을 계산하는 것과 같은 원리로 구할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주의할 점은 좌표가 0 &quot;이상&quot; 10^5 &quot;이하&quot;로 들어올 수 있으므로 이 처리를 잘해주어야 한다. (하나의 트리에서 값을 10^5 + 1개 이상 담당하도록 해야함)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 퍼시스턴트 세그먼트 트리는 인덱스를 이용하여 구현하는 방법이 있고 포인터를 이용하여 구현하는 방법이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;백준 BOJ 11012 Egg&lt;/b&gt; 문제의 풀이를 구글링해보면 대부분 인덱스 기반으로 구현되어있을 것인데, 아래는 포인터를 이용하여 구현하는 방법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1671020707187&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

const int MAX = 1e5 + 1;

struct node {
    node *l, *r; int x;
    node() { l = r = NULL, x = 0; }
};

node *add(node *cur, int b, int e, int idx, int val) {
    if(cur == NULL) cur = new node();

    if(idx &amp;lt; b || e &amp;lt; idx) return cur;

    if(b == e) {
        node *ret = new node();

        ret-&amp;gt;x = cur-&amp;gt;x + 1;

        return ret;
    }

    node *ret = new node();

    node *ln = add(cur-&amp;gt;l, b, (b+e)/2, idx, val);
    node *rn = add(cur-&amp;gt;r, (b+e)/2 + 1, e, idx, val);

    ret-&amp;gt;l = ln, ret-&amp;gt;r = rn, ret-&amp;gt;x = ln-&amp;gt;x + rn-&amp;gt;x;

    return ret;
}

int sum(node *cur, int b, int e, int l, int r) {
    if(cur == NULL) return 0;

    if(r &amp;lt; b || e &amp;lt; l) return 0;
    if(l &amp;lt;= b &amp;amp;&amp;amp; e &amp;lt;= r) return cur-&amp;gt;x;

    return sum(cur-&amp;gt;l, b, (b+e)/2, l, r) + sum(cur-&amp;gt;r, (b+e)/2 + 1, e, l, r);
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    while(T--) {
        int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

        vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; v(MAX+1);

        for(int i=0; i&amp;lt;N; i++) {
            int x, y; cin &amp;gt;&amp;gt; x &amp;gt;&amp;gt; y;

            v[x+1].push_back(y+1);
        }

        node *u[MAX+1];
        u[0] = new node();

        for(int i=1; i&amp;lt;=MAX; i++) {
            u[i] = new node();

            u[i]-&amp;gt;l = u[i-1]-&amp;gt;l, u[i]-&amp;gt;r = u[i-1]-&amp;gt;r, u[i]-&amp;gt;x = u[i-1]-&amp;gt;x;

            for(int j=0; j&amp;lt;v[i].size(); j++)
                u[i] = add(u[i], 1, MAX, v[i][j], 1);
        }

        int ans = 0;

        while(M--) {
            int a, b, c, d; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b &amp;gt;&amp;gt; c &amp;gt;&amp;gt; d;

            ans += sum(u[b+1], 1, MAX, c+1, d+1)
                   - sum(u[a], 1, MAX, c+1, d+1);
        }

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 13537번 : 수열과 쿼리 1&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;머지 소트 트리&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;길이 10만 이하의 수열이 주어지고, 10만 개 이하의 쿼리에 대해 구간 [i, j]가 주어지면 해당 구간에서 k보다 큰 원소의 개수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;세그먼트 트리와 동일하게 각 구간을 담당하는 노드가 있고, 각 노드에 담당 구간 원소들이 정렬된 벡터를 가지고 있다면 log 시간에 해결이 가능할 것&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 &lt;u&gt;이렇게 구현을 하는 경우 트리의 높이는 log N 정도이고, 하나의 층에 총 N개의 원소가 있으므로 공간복잡도 역시 O(N log N)으로 메모리 초과를 발생시키지 않는다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것이 &lt;b&gt;머지 소트 트리(Merge Sort Tree)&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구현이 문제인데, 이것은 merge 함수를 이용하여 생각보다 간단하게 구현이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자세한 구현은 아래의 코드를 참고하면 도움이 될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1671021619319&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct mergeSortTree {
    vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; v;

    void init(int n, int b, int e, vector&amp;lt;int&amp;gt; &amp;amp;u) {
        if(b == e) {
            v[n].push_back(u[b-1]);
            return;
        }

        init(n*2, b, (b+e)/2, u);
        init(n*2+1, (b+e)/2+1, e, u);

        v[n].resize(v[n*2].size() + v[n*2+1].size());
        merge(v[n*2].begin(), v[n*2].end(), v[n*2+1].begin(), v[n*2+1].end(), v[n].begin());
    }

    int gt(int n, int b, int e, int l, int r, int x) {
        if(r &amp;lt; b || e &amp;lt; l) return 0;

        if(l &amp;lt;= b &amp;amp;&amp;amp; e &amp;lt;= r)
            return v[n].end() - upper_bound(v[n].begin(), v[n].end(), x);

        return gt(n*2, b, (b+e)/2, l, r, x) + gt(n*2+1, (b+e)/2+1, e, l, r, x);
    }
};

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    mergeSortTree f;
    f.v.resize(1&amp;lt;&amp;lt;18);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;int&amp;gt; v(N);
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];

    f.init(1, 1, N, v);

    int M; cin &amp;gt;&amp;gt; M;

    while(M--) {
        int a, b, c; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b &amp;gt;&amp;gt; c;

        int ans = f.gt(1, 1, N, a, b, c);

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 13544번 : 수열과 쿼리 3&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;머지 소트 트리&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 문제와 거의 동일하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드 역시 거의 비슷하다. 아래에 첨부해두었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1671021711542&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct mergeSortTree {
    vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; v;

    void init(int n, int b, int e, vector&amp;lt;int&amp;gt; &amp;amp;u) {
        if(b == e) {
            v[n].push_back(u[b-1]);
            return;
        }

        init(n*2, b, (b+e)/2, u);
        init(n*2+1, (b+e)/2+1, e, u);

        v[n].resize(v[n*2].size() + v[n*2+1].size());
        merge(v[n*2].begin(), v[n*2].end(), v[n*2+1].begin(), v[n*2+1].end(), v[n].begin());
    }

    int gt(int n, int b, int e, int l, int r, int x) {
        if(r &amp;lt; b || e &amp;lt; l) return 0;

        if(l &amp;lt;= b &amp;amp;&amp;amp; e &amp;lt;= r)
            return v[n].end() - upper_bound(v[n].begin(), v[n].end(), x);

        return gt(n*2, b, (b+e)/2, l, r, x) + gt(n*2+1, (b+e)/2+1, e, l, r, x);
    }
};

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    mergeSortTree f;
    f.v.resize(1&amp;lt;&amp;lt;18);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;int&amp;gt; v(N);
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];

    f.init(1, 1, N, v);

    int M; cin &amp;gt;&amp;gt; M;

    int ans = 0;

    while(M--) {
        int a, b, c; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b &amp;gt;&amp;gt; c;

        a ^= ans, b ^= ans, c ^= ans;

        ans = f.gt(1, 1, N, a, b, c);

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 7469번 : K번째 수&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;머지 소트 트리&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역시 쿼리 문제인데, 주어진 구간의 원소들을 정렬했을 때 K번째로 작은 수를 구하는 쿼리를 처리하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;머지 소트 트리로 해결이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방법은 &lt;b&gt;이분 탐색&lt;/b&gt;을 활용하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt; 적당한 x를 잡아서 x 이하인 수의 개수를 구하고, 이 x 이하인 수가 k개인 가장 작은 x를 이분 탐색&lt;/u&gt;으로 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구현은 아래에 있으며, ord 함수를 중점적으로 보면 될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1671021916259&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct mergeSortTree {
    vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; v;

    void init(int n, int b, int e, vector&amp;lt;int&amp;gt; &amp;amp;u) {
        if(b == e) {
            v[n].push_back(u[b-1]);
            return;
        }

        init(n*2, b, (b+e)/2, u);
        init(n*2+1, (b+e)/2+1, e, u);

        v[n].resize(v[n*2].size() + v[n*2+1].size());
        merge(v[n*2].begin(), v[n*2].end(), v[n*2+1].begin(), v[n*2+1].end(), v[n].begin());
    }

    int ord(int n, int b, int e, int l, int r, int x) {
        if(r &amp;lt; b || e &amp;lt; l) return 0;

        if(l &amp;lt;= b &amp;amp;&amp;amp; e &amp;lt;= r)
            return upper_bound(v[n].begin(), v[n].end(), x) - v[n].begin();

        return ord(n*2, b, (b+e)/2, l, r, x) + ord(n*2+1, (b+e)/2+1, e, l, r, x);
    }
};

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    mergeSortTree f;
    f.v.resize(1&amp;lt;&amp;lt;18);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    vector&amp;lt;int&amp;gt; v(N);
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];

    f.init(1, 1, N, v);

    while(M--) {
        int a, b, c; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b &amp;gt;&amp;gt; c;

        int l = -1e9, r = 1e9, ans = 1e9;

        while(l &amp;lt;= r) {
            int m = (l + r) / 2;

            int x = f.ord(1, 1, N, a, b, m);

            if(x &amp;gt;= c) {
                ans = min(ans, m);
                r = m - 1;
            }
            else l = m + 1;
        }

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 13310번 : 먼 별&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Diamond V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;회전하는 캘리퍼스, 삼분 탐색&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3만 개 이하의 2차원 좌표 상의 점과 하루 이동하는 거리가 주어지고, 10^7 이하의 일 수가 주어질 때, 주어진 기간 내에서 가장 먼 두 별의 거리가 가장 가까운 날짜를 구하고, 그 때의 거리를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 우선 특정 날짜에서 별의 분포에 대해 가장 먼 두 별의 거리를 구하는 방법을 생각해보아야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것은 &lt;b&gt;볼록 껍질 (Convex Hull)&lt;/b&gt; + &lt;b&gt;회전하는 캘리퍼스 (Rotating Calipers)&lt;/b&gt; 알고리즘으로 구현할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 날짜에 따른 별들의 거리 분포에 대해 생각해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기선 엄밀한 증명은 하지 않겠지만, 직관적으로 보았을 때 별들의 최대 거리가 시간이 지남에 따라 증가하거나, 감소하거나, 또는 감소하다가 증가하는 세 가지 경우가 전부이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 최대 1개의 극값을 갖는 경우 &lt;b&gt;삼분 탐색&lt;/b&gt;으로 답을 찾을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 블로그에 컨벡스 헐, 회전하는 캘리퍼스, 삼분 탐색 알고리즘을 이전에 모두 정리해두었으므로 여기에서는 풀이 코드만 첨부한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 삼분점에서의 가장 먼 두 별의 거리를 가지고 범위를 적절히 좁혀나간 뒤, 좁혀진 범위 내에서의 최소 거리를 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 삼분 탐색 문제를 많이 안 풀어봤으면 부등호 범위가 애매할 수 있다. (나도 오랜만에 풀어서 잠시 헷갈렸다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;양단 좌표가 l, r이고 삼분점이 각각 m1, m2라고 할 때 이 문제에서는 &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;f(m1) == f(m2)인 경우 r = m2로 범위를 좁혀야&lt;/span&gt; &lt;/b&gt;되는데, 그 이유는 &lt;u&gt;가장 먼 두 별의 거리가 최소인 날짜가 여러 개일 경우 가장 빠른 촬영일을 출력하면 된다고 하였으므로 오른쪽 끝을 왼쪽으로 붙여주면 된다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 이 처리를 하지 않는다면 삼분 탐색이 끝나도 f(x) 값이 동일한 날이 매우 많아 l ~ r 범위가 커진다면 시간 초과가 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1671022407396&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct P { int x, y; };

P operator-(P a, P b) {
    P c;
    c.x = a.x - b.x;
    c.y = a.y - b.y;
    return c;
}

int N, M;
vector&amp;lt;P&amp;gt; v, u, w;

int ccw(P a, P b, P c) {
    return a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y);
}

bool cmp(P &amp;amp;a, P &amp;amp;b) {
    int x = ccw(v[0], a, b);

    if(x != 0) return x &amp;gt; 0;
    else if(a.y != b.y) return a.y &amp;lt; b.y;
    else return a.x &amp;lt; b.x;
}

int f(int m) {
    v.clear(); v.resize(N);

    for(int i=0; i&amp;lt;N; i++) {
        v[i].x = u[i].x + w[i].x * m;
        v[i].y = u[i].y + w[i].y * m;
    }

    for(int i=1; i&amp;lt;N; i++)
            if(v[i].y &amp;lt; v[0].y || (v[i].y == v[0].y &amp;amp;&amp;amp; v[i].x &amp;lt; v[0].x)) swap(v[i], v[0]);

    sort(v.begin()+1, v.end(), cmp);

    stack&amp;lt;P&amp;gt; s;

    s.push(v[0]);
    s.push(v[1]);

    for(int i=2; i&amp;lt;N; i++) {
        while(s.size() &amp;gt;= 2) {
            P a = s.top(); s.pop();
            P b = s.top();

            if(ccw(b, a, v[i]) &amp;gt; 0) {
                s.push(a);
                break;
            }
        }
        s.push(v[i]);
    }

    vector&amp;lt;P&amp;gt; u(s.size());
    while(!s.empty()) {
        u[s.size()-1] = s.top();
        s.pop();
    }

    int l = 0, r = 0;
    for(int i=0; i&amp;lt;u.size(); i++) {
        if(u[i].x &amp;lt; u[l].x) l = i;
        if(u[i].x &amp;gt; u[r].x) r = i;
    }

    int ret = pow(u[l].x - u[r].x, 2) + pow(u[l].y - u[r].y, 2);
    P o = {0, 0};

    for(int i=0; i&amp;lt;u.size(); i++) {
        int nl = (l+1) % u.size();
        int nr = (r+1) % u.size();

        if(ccw(o, u[nl] - u[l], u[r] - u[nr]) &amp;gt; 0) l = nl;
        else r = nr;

        ret = max(ret, (u[l].x - u[r].x) * (u[l].x - u[r].x)
                        + (u[l].y - u[r].y) * (u[l].y - u[r].y));
    }

    return ret;
}

signed main() {
    ios_base::sync_with_stdio(0), cin.tie(0);

    cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    u.resize(N), w.resize(N);

    for(int i=0; i&amp;lt;N; i++)
        cin &amp;gt;&amp;gt; u[i].x &amp;gt;&amp;gt; u[i].y &amp;gt;&amp;gt; w[i].x &amp;gt;&amp;gt; w[i].y;

    int l = 0, r = M;

    while(l+3 &amp;lt;= r) {
        int m1 = (l*2 + r) / 3;
        int m2 = (l + r*2) / 3;

        if(f(m1) &amp;gt; f(m2)) l = m1;
        else r = m2;
    }

    int dis = LLONG_MAX, day;

    for(int i=l; i&amp;lt;=r; i++) {
        int val = f(i);

        if(val &amp;lt; dis) {
            dis = val;
            day = i;
        }
    }

    cout &amp;lt;&amp;lt; day &amp;lt;&amp;lt; &quot;\n&quot;;
    cout &amp;lt;&amp;lt; dis &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 1199번 : 오일러 회로&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;오일러 경로&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래프에서의 N x N 크기의 인접 행렬이 주어질 때, 오일러 회로대로 방문하는 정점들을 순서대로 출력하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;오일러 회로&lt;/b&gt;란 &lt;u&gt;그래프에서 모든 간선을 지나고 다시 출발점으로 돌아오는 &quot;회로&quot;&lt;/u&gt;를 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오일러 회로 자체를 구현하는 것은 다음과 같은 아이디어로 구현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회로를 따라 이동하면 다시 원래 자리로 돌아오므로 여러 개의 회로를 쪼개어 찾은 뒤 이 경로들을 합쳐주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것은 &lt;u&gt;DFS를 재귀적으로 구현&lt;/u&gt;하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 이 문제에 한해서는 이렇게 구현된 Hierholzer 알고리즘은 O(VE)의 시간복잡도를 가지는데, 여기에서는 O(E log V) 이하로 줄여야 통과가 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 나의 경우 세그먼트 트리를 활용하여 꼭짓점들을 log 시간에 인접 리스트에서 탐색하여 추가하거나 제거할 수 있도록 구현해주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1671022714940&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct segmentTree {
    vector&amp;lt;int&amp;gt; v;

    void upd(int n, int b, int e, int idx, int val) {
        if(b == e) {
            v[n] += val;
            return;
        }

        if(idx &amp;lt;= (b+e)/2) upd(n*2, b, (b+e)/2, idx, val);
        else upd(n*2 + 1, (b+e)/2 + 1, e, idx, val);

        v[n] = v[n*2] + v[n*2 + 1];
    }

    int sum(int n, int b, int e, int l, int r) {
        if(r &amp;lt; b || e &amp;lt; l) return 0;
        if(l &amp;lt;= b &amp;amp;&amp;amp; e &amp;lt;= r) return v[n];

        return sum(n*2, b, (b+e)/2, l, r)
                + sum(n*2 + 1, (b+e)/2 + 1, e, l, r);
    }

    int kth(int n, int b, int e, int ran) {
        if(b == e) return b;

        if(ran &amp;lt;= v[n*2]) return kth(n*2, b, (b+e)/2, ran);
        else return kth(n*2+1, (b+e)/2+1, e, ran-v[n*2]);
    }
};

struct EulerianPath {
    segmentTree adj[1001];

    int N, start = 0;
    stack&amp;lt;int&amp;gt; s;

    void init() {
        cin &amp;gt;&amp;gt; N;

        for(int i=1; i&amp;lt;=N; i++) {
            adj[i].v.resize(N*4);

            for(int j=1; j&amp;lt;=N; j++) {
                int x; cin &amp;gt;&amp;gt; x;

                adj[i].upd(1, 1, N, j, x);
            }
        }
    }

    bool exist() {
        for(int i=1; i&amp;lt;=N; i++) {
            int cnt = adj[i].sum(1, 1, N, 1, N);

            if(cnt % 2 == 1) return false;

            if(start == 0 &amp;amp;&amp;amp; cnt &amp;gt; 0) start = i;
        }

        return true;
    }

    void dfs(int x) {
        while(adj[x].sum(1, 1, N, 1, N) &amp;gt; 0) {
            int y = adj[x].kth(1, 1, N, 1);

            adj[x].upd(1, 1, N, y, -1);
            adj[y].upd(1, 1, N, x, -1);

            dfs(y);
        }

        s.push(x);
    }
};

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    EulerianPath f; f.init();

    if(!f.exist()) {
        cout &amp;lt;&amp;lt; -1 &amp;lt;&amp;lt; &quot;\n&quot;;
        return 0;
    }

    f.dfs(f.start);

    while(!f.s.empty()) {
        cout &amp;lt;&amp;lt; f.s.top() &amp;lt;&amp;lt; &quot; &quot;;
        f.s.pop();
    }
    cout &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 9463번 : 순열 그래프&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;세그먼트 트리&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;508&quot; data-origin-height=&quot;167&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6Glo1/btrTFgBWCWP/HuKAxZkJ82kQrK7A7WX2i1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6Glo1/btrTFgBWCWP/HuKAxZkJ82kQrK7A7WX2i1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6Glo1/btrTFgBWCWP/HuKAxZkJ82kQrK7A7WX2i1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6Glo1%2FbtrTFgBWCWP%2FHuKAxZkJ82kQrK7A7WX2i1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;508&quot; height=&quot;167&quot; data-origin-width=&quot;508&quot; data-origin-height=&quot;167&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 기본적인 세그먼트 트리 문제인데 워낙 웰노운이라 여기에 간단히만 정리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 2개의 순열이 주어지고, 위 아래에서 같은 수끼리 연결했을 때 교차점의 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심은 넘버링 부분인데, 웰노운이긴 하지만 깔끔하기도 하고 기억해둘만 해서 아래에 정리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 &lt;span style=&quot;color: #ee2323;&quot;&gt;윗줄에서 i번째로 입력받은 x에 대해 &lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;v[x] = i&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;로 저장해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 &lt;span style=&quot;color: #ee2323;&quot;&gt;아랫줄에서 i번째로 입력받은 x에 대해 &lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;u[i] = v[x]&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;로 저장해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 &lt;u&gt;u[i]는 아랫줄의 i번째 수가 있는 윗줄의 인덱스&lt;/u&gt;가 되므로, 이제 세그먼트 트리로 매우 쉽게 처리해줄 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1671022820515&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct segmentTree {
    vector&amp;lt;int&amp;gt; v;

    void upd(int n, int b, int e, int idx, int val) {
        if(b == e) {
            v[n] += val;
            return;
        }

        if(idx &amp;lt;= (b+e)/2) upd(n*2, b, (b+e)/2, idx, val);
        else upd(n*2 + 1, (b+e)/2 + 1, e, idx, val);

        v[n] = v[n*2] + v[n*2 + 1];
    }

    int sum(int n, int b, int e, int l, int r) {
        if(r &amp;lt; b || e &amp;lt; l) return 0;
        if(l &amp;lt;= b &amp;amp;&amp;amp; e &amp;lt;= r) return v[n];

        return sum(n*2, b, (b+e)/2, l, r)
                + sum(n*2 + 1, (b+e)/2 + 1, e, l, r);
    }
};

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    while(T--) {
        int N; cin &amp;gt;&amp;gt; N;

        segmentTree f; f.v.resize(N*4);

        vector&amp;lt;int&amp;gt; v(N+1), u(N+1);

        for(int i=1; i&amp;lt;=N; i++) {
            int x; cin &amp;gt;&amp;gt; x;

            v[x] = i;
        }

        for(int i=1; i&amp;lt;=N; i++) {
            int x; cin &amp;gt;&amp;gt; x;

            u[i] = v[x];
        }

        int ans = 0;

        for(int i=1; i&amp;lt;=N; i++) {
            ans += (u[i] - 1) - f.sum(1, 1, N, 1, u[i]);

            f.upd(1, 1, N, u[i], 1);
        }

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/알고리즘 공부 내용 정리</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/644</guid>
      <comments>https://restudycafe.tistory.com/644#entry644comment</comments>
      <pubDate>Wed, 14 Dec 2022 22:03:41 +0900</pubDate>
    </item>
    <item>
      <title>백준 BOJ 2-SAT 알고리즘 심화 문제 풀이</title>
      <link>https://restudycafe.tistory.com/643</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 1739번 : 도로 정비하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;2-SAT&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 가로 도로에 대해서 왼쪽 일방 통행의 경우 T, 오른쪽이면 F로 임의로 두자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마찬가지로 세로 도로에 대해서도 위 방향은 T, 아래 방향을 F로 두자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방향은 푸는 사람이 정의하면 된다. 명제 연결할 때만 제대로 연결하면 관계없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 어떤 점에서 다른 점으로의 이동에 대해, 두 가지 경로가 있으므로, 두 경로에 대해 (A and B) or (C and D)꼴이 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것을 식을 풀어서 (나는 분배 법칙으로 풀었다.) (E or F) and (G or H) 꼴로 바꾼 뒤 2-SAT를 적용해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 2-SAT에 다른 알고리즘이 접목된 문제도 아닌데 난이도가&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Platinum I&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐하면 나눠야 할 조건 분기가 너무 많고, 동시에 각각 연결해야 할 명제의 개수도 매우 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래에 모든 경우의 수를 정리해두었으니 그림을 참고하면 좋을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1513&quot; data-origin-height=&quot;1881&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EPZDL/btrSeOT3h4f/KmiXt5ClD4EJz8FoIjdL91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EPZDL/btrSeOT3h4f/KmiXt5ClD4EJz8FoIjdL91/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EPZDL/btrSeOT3h4f/KmiXt5ClD4EJz8FoIjdL91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEPZDL%2FbtrSeOT3h4f%2FKmiXt5ClD4EJz8FoIjdL91%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;473&quot; height=&quot;588&quot; data-origin-width=&quot;1513&quot; data-origin-height=&quot;1881&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1527&quot; data-origin-height=&quot;3481&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JykEJ/btrSagD3i39/CorCxYkDBv19vKpvduK5Y1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JykEJ/btrSagD3i39/CorCxYkDBv19vKpvduK5Y1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JykEJ/btrSagD3i39/CorCxYkDBv19vKpvduK5Y1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJykEJ%2FbtrSagD3i39%2FCorCxYkDBv19vKpvduK5Y1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;480&quot; height=&quot;1094&quot; data-origin-width=&quot;1527&quot; data-origin-height=&quot;3481&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;darr; 풀이 코드는 여기에 있다.&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1669558228913&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj, scc;
vector&amp;lt;int&amp;gt; nnum, cnum;
int ncnt = 0, ccnt = 0;

stack&amp;lt;int&amp;gt; s;
vector&amp;lt;bool&amp;gt; ch;

int y(int x) {
    if(x &amp;lt; 0) return (-x)*2 - 2;
    else return x*2 - 1;
}

int n(int x) {
    x = y(x);

    if(x % 2 == 0) return x + 1;
    else return x - 1;
}

int dfs(int x) {
    nnum[x] = ++ncnt;
    s.push(x);

    int tmp = nnum[x];

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(nnum[y] == 0) tmp = min(tmp, dfs(y));
        else if(!ch[y]) tmp = min(tmp, nnum[y]);
    }

    if(tmp == nnum[x]) {
        vector&amp;lt;int&amp;gt; v;
        ccnt++;

        while(true) {
            int y = s.top();
            s.pop();

            v.push_back(y);

            ch[y] = true;
            cnum[y] = ccnt;

            if(y == x) break;
        }

        sort(v.begin(), v.end());

        scc.push_back(v);
    }

    return tmp;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    while(T--) {
        int R, C, K; cin &amp;gt;&amp;gt; R &amp;gt;&amp;gt; C &amp;gt;&amp;gt; K;

        int N = R + C;

        adj.clear(); adj.resize(N*2);

        while(K--) {
            int bx, by, ex, ey; cin &amp;gt;&amp;gt; bx &amp;gt;&amp;gt; by &amp;gt;&amp;gt; ex &amp;gt;&amp;gt; ey;

            if(bx == ex &amp;amp;&amp;amp; by &amp;lt; ey) adj[y(bx)].push_back(n(bx));
            else if(bx == ex &amp;amp;&amp;amp; by &amp;gt; ey) adj[n(bx)].push_back(y(bx));
            else if(bx &amp;gt; ex &amp;amp;&amp;amp; by == ey) adj[n(R+by)].push_back(y(R+by));
            else if(bx &amp;lt; ex &amp;amp;&amp;amp; by == ey) adj[y(R+by)].push_back(n(R+by));
            else if(bx &amp;lt; ex &amp;amp;&amp;amp; by &amp;lt; ey) {
                adj[y(bx)].push_back(n(ex));
                adj[y(ex)].push_back(n(bx));
                adj[y(bx)].push_back(n(R+by));
                adj[y(R+by)].push_back(n(bx));
                adj[y(ex)].push_back(n(R+ey));
                adj[y(R+ey)].push_back(n(ex));
                adj[y(R+ey)].push_back(n(R+by));
                adj[y(R+by)].push_back(n(R+ey));
            }
            else if(bx &amp;lt; ex &amp;amp;&amp;amp; by &amp;gt; ey) {
                adj[n(bx)].push_back(y(ex));
                adj[n(ex)].push_back(y(bx));
                adj[n(bx)].push_back(n(R+by));
                adj[y(R+by)].push_back(y(bx));
                adj[n(ex)].push_back(n(R+ey));
                adj[y(R+ey)].push_back(y(ex));
                adj[y(R+ey)].push_back(n(R+by));
                adj[y(R+by)].push_back(n(R+ey));
            }
            else if(bx &amp;gt; ex &amp;amp;&amp;amp; by &amp;lt; ey) {
                adj[y(bx)].push_back(n(ex));
                adj[y(ex)].push_back(n(bx));
                adj[y(bx)].push_back(y(R+by));
                adj[n(R+by)].push_back(n(bx));
                adj[y(ex)].push_back(y(R+ey));
                adj[n(R+ey)].push_back(n(ex));
                adj[n(R+ey)].push_back(y(R+by));
                adj[n(R+by)].push_back(y(R+ey));
            }
            else if(bx &amp;gt; ex &amp;amp;&amp;amp; by &amp;gt; ey) {
                adj[n(bx)].push_back(y(ex));
                adj[n(ex)].push_back(y(bx));
                adj[n(bx)].push_back(y(R+by));
                adj[n(R+by)].push_back(y(bx));
                adj[n(ex)].push_back(y(R+ey));
                adj[n(R+ey)].push_back(y(ex));
                adj[n(R+ey)].push_back(y(R+by));
                adj[n(R+by)].push_back(y(R+ey));
            }
        }

        nnum.clear(); nnum.resize(N*2);
        cnum.clear(); cnum.resize(N*2);
        ch.clear();   ch.resize(N*2);

        scc.clear();
        ncnt = ccnt = 0;

        for(int i=0; i&amp;lt;N*2; i++)
            if(nnum[i] == 0) dfs(i);

        bool check = true;

        for(int i=0; i&amp;lt;N; i++) {
            if(cnum[i*2] == cnum[i*2 + 1]) {
                check = false;
                break;
            }
        }

        if(check) cout &amp;lt;&amp;lt; &quot;Yes\n&quot;;
        else cout &amp;lt;&amp;lt; &quot;No\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 5009번 : 유치원&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;2-SAT, 이분 탐색&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2-SAT에 이분 탐색을 결합한 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;큰 틀에서는 적절한 T를 찾기 위해 0 ~ N-1 사이에서 이분 탐색을 하며 T를 찾아주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2-SAT 문제로 치환하기 위해, 특정 번호 i가 0반에 속하는지의 여부, 1반에 속하는지의 여부, 2반에 속하는지의 여부를 각각 bool 변수로 생각해서 3N개의 변수를 만들어주고, 명제 관계만 잘 연결해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 T를 기준으로 등수가 더 낮은 번호와는 같은 반이 되면 안 되므로, &quot;i가 x반이면 &amp;rarr; j는 x반이 아니다&quot;, 동시에 &quot;j가 x반이면 &amp;rarr; i는 x반이 아니다&quot; 이런 식으로 명제들을 연결해줄 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 명제 조건을 다 설명하기엔 길기 때문에 풀이 코드를 참고하면 도움이 될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1669557867773&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj, scc;
vector&amp;lt;int&amp;gt; nnum, cnum;
int ncnt = 0, ccnt = 0;

stack&amp;lt;int&amp;gt; s;
vector&amp;lt;bool&amp;gt; ch;

int y(int x) {
    if(x &amp;lt; 0) return (-x)*2 - 2;
    else return x*2 - 1;
}

int n(int x) {
    x = y(x);

    if(x % 2 == 0) return x + 1;
    else return x - 1;
}

int dfs(int x) {
    nnum[x] = ++ncnt;
    s.push(x);

    int tmp = nnum[x];

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(nnum[y] == 0) tmp = min(tmp, dfs(y));
        else if(!ch[y]) tmp = min(tmp, nnum[y]);
    }

    if(tmp == nnum[x]) {
        vector&amp;lt;int&amp;gt; v;
        ccnt++;

        while(true) {
            int y = s.top();
            s.pop();

            v.push_back(y);

            ch[y] = true;
            cnum[y] = ccnt;

            if(y == x) break;
        }

        sort(v.begin(), v.end());

        scc.push_back(v);
    }

    return tmp;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;int&amp;gt; v(N+1);
    vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; u(N+1, vector&amp;lt;int&amp;gt;(N));

    for(int i=1; i&amp;lt;=N; i++) {
        cin &amp;gt;&amp;gt; v[i];

        for(int j=1; j&amp;lt;=N-1; j++) cin &amp;gt;&amp;gt; u[i][j];
    }

    int l = 0, r = N-1, ans = N-1;
    int M = N * 3;

    while(l &amp;lt;= r) {
        int m = (l + r) / 2;

        adj.clear(); adj.resize(M*2);

        for(int i=1; i&amp;lt;=N; i++) {
            adj[y(v[i]*N + i)].push_back(n(v[i]*N + i));

            int a = ((v[i] + 1) % 3)*N + i;
            int b = ((v[i] + 2) % 3)*N + i;

            adj[n(a)].push_back(y(b));
            adj[n(b)].push_back(y(a));

            for(int j=m+1; j&amp;lt;=N-1; j++)
                for(int k=0; k&amp;lt;3; k++) {
                    if(k == v[i]) continue;

                    adj[y(k*N + i)].push_back(n(k*N + u[i][j]));
                    adj[y(k*N + u[i][j])].push_back(n(k*N + i));
                }
        }

        nnum.clear(); nnum.resize(M*2);
        cnum.clear(); cnum.resize(M*2);
        ch.clear();   ch.resize(M*2);

        scc.clear();
        ncnt = ccnt = 0;

        for(int i=0; i&amp;lt;M*2; i++)
            if(nnum[i] == 0) dfs(i);

        bool check = true;

        for(int i=0; i&amp;lt;M; i++) {
            if(cnum[i*2] == cnum[i*2 + 1]) {
                check = false;
                break;
            }
        }

        if(check) {
            ans = min(ans, m);
            r = m - 1;
        }
        else l = m + 1;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 2519번 : 막대기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Diamond V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;2-SAT, 선분 교차 판정&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2-SAT 문제에 선분 교차 판정이 접목된 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구현이 쉽지 않은 두 알고리즘이 모두 사용되기 때문에 다른 2-SAT 문제에 비해 구현량이 매우 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 두 가지를 구현할 줄만 알면 간단한 명제 식 몇 개만 풀면 문제가 쉽게 풀리므로, 곧 투표에 의해 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum&lt;/b&gt;&lt;/span&gt;으로 난이도가 하향될 것 같기도 하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1669558293056&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { int x, y; };

bool operator== (s a, s b) {
    if(a.x == b.x &amp;amp;&amp;amp; a.y == b.y) return true;
    else return false;
}
bool operator&amp;gt;= (s a, s b) {
    if(a.x &amp;gt; b.x || (a.x == b.x &amp;amp;&amp;amp; a.y &amp;gt;= b.y)) return true;
    else return false;
}
bool operator&amp;lt;= (s a, s b) {
    if(a.x &amp;lt; b.x || (a.x == b.x &amp;amp;&amp;amp; a.y &amp;lt;= b.y)) return true;
    else return false;
}
bool operator&amp;gt; (s a, s b) {
    if(a.x &amp;gt; b.x || (a.x == b.x &amp;amp;&amp;amp; a.y &amp;gt; b.y)) return true;
    else return false;
}
bool operator&amp;lt; (s a, s b) {
    if(a.x &amp;lt; b.x || (a.x == b.x &amp;amp;&amp;amp; a.y &amp;lt; b.y)) return true;
    else return false;
}

int ccw(s a, s b, s c) {
    int val = a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y);

    if(val == 0) return 0;
    else if(val &amp;gt; 0) return 1;
    else if(val &amp;lt; 0) return -1;
}

bool cross, overlap;
double cx, cy;

void coor(s a, s b, s c, s d) {
    double X = (a.x * b.y - a.y * b.x) * (c.x - d.x) - (a.x - b.x) * (c.x * d.y - c.y * d.x);
    double Y = (a.x * b.y - a.y * b.x) * (c.y - d.y) - (a.y - b.y) * (c.x * d.y - c.y * d.x);
    double div = (a.x - b.x) * (c.y - d.y) - (a.y - b.y) * (c.x - d.x);

    if(div == 0) {
        if(b == c &amp;amp;&amp;amp; a &amp;lt;= c) cx = b.x, cy = b.y, overlap = false;
        else if(a == d &amp;amp;&amp;amp; c &amp;lt;= a) cx = a.x, cy = a.y, overlap = false;
        else overlap = true;
    }
    else cx = X / div, cy = Y / div, overlap = false;
}

void inter(s a, s b, s c, s d) {
    int val1 = ccw(a, b, c) * ccw(a, b, d);
    int val2 = ccw(c, d, a) * ccw(c, d, b);

    if(val1 == 0 &amp;amp;&amp;amp; val2 == 0) {
        if(a &amp;gt; b) swap(a, b);
        if(c &amp;gt; d) swap(c, d);

        if(a &amp;lt;= d &amp;amp;&amp;amp; b &amp;gt;= c) {
            cross = true;
            coor(a, b, c, d);
        }
        else cross = false;
    }
    else {
        if(val1 &amp;lt;= 0 &amp;amp;&amp;amp; val2 &amp;lt;= 0) {
            cross = true;
            coor(a, b, c, d);
        }
        else cross = false;
    }
}

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj, scc;
vector&amp;lt;int&amp;gt; nnum, cnum;
int ncnt = 0, ccnt = 0;

stack&amp;lt;int&amp;gt; st;
vector&amp;lt;bool&amp;gt; ch;

int dfs(int x) {
    nnum[x] = ++ncnt;
    st.push(x);

    int tmp = nnum[x];

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(nnum[y] == 0) tmp = min(tmp, dfs(y));
        else if(!ch[y]) tmp = min(tmp, nnum[y]);
    }

    if(tmp == nnum[x]) {
        vector&amp;lt;int&amp;gt; v;
        ccnt++;

        while(true) {
            int y = st.top();
            st.pop();

            v.push_back(y);

            ch[y] = true;
            cnum[y] = ccnt;

            if(y == x) break;
        }

        sort(v.begin(), v.end());

        scc.push_back(v);
    }

    return tmp;
}

int cvt(int x) {
    if(x &amp;lt; 0) return (-x)*2 - 2;
    else return x*2 - 1;
}

int cvtn(int x) {
    x = cvt(x);

    if(x % 2 == 0) return x + 1;
    else return x - 1;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    N *= 3;

    vector&amp;lt;vector&amp;lt;s&amp;gt;&amp;gt; v(N+1, vector&amp;lt;s&amp;gt;(2));

    for(int i=1; i&amp;lt;=N; i++)
        cin &amp;gt;&amp;gt; v[i][0].x &amp;gt;&amp;gt; v[i][0].y &amp;gt;&amp;gt; v[i][1].x &amp;gt;&amp;gt; v[i][1].y;

    adj.resize(N*2);

    for(int i=1; i&amp;lt;=N; i+=3) {
        adj[cvt(i)].push_back(cvtn(i+1));
        adj[cvt(i)].push_back(cvtn(i+2));

        adj[cvt(i+1)].push_back(cvtn(i));
        adj[cvt(i+1)].push_back(cvtn(i+2));

        adj[cvt(i+2)].push_back(cvtn(i));
        adj[cvt(i+2)].push_back(cvtn(i+1));
    }

    for(int i=1; i&amp;lt;=N; i++)
        for(int j=i+1; j&amp;lt;=N; j++) {
            inter(v[i][0], v[i][1], v[j][0], v[j][1]);

            if(cross) {
                adj[cvtn(i)].push_back(cvt(j));
                adj[cvtn(j)].push_back(cvt(i));
            }
        }

    nnum.resize(N*2);
    cnum.resize(N*2);
    ch.resize(N*2);

    for(int i=0; i&amp;lt;N*2; i++)
        if(nnum[i] == 0) dfs(i);

    bool check = true;

    for(int i=0; i&amp;lt;N; i++) {
        if(cnum[i*2] == cnum[i*2 + 1]) {
            check = false;
            break;
        }
    }

    if(!check) {
        cout &amp;lt;&amp;lt; -1 &amp;lt;&amp;lt; &quot;\n&quot;;
        return 0;
    }

    vector&amp;lt;pair&amp;lt;int, int&amp;gt;&amp;gt; p(N*2);
    for(int i=0; i&amp;lt;N*2; i++) p[i] = {cnum[i], i};

    sort(p.begin(), p.end(), greater&amp;lt;pair&amp;lt;int, int&amp;gt;&amp;gt;());

    vector&amp;lt;int&amp;gt; tf(N*2, -1);

    for(int i=0; i&amp;lt;N*2; i++) {
        int x = p[i].second;

        if(tf[x/2] == -1) {
            if(x % 2 == 1) tf[x/2] = 0;
            else tf[x/2] = 1;
        }
    }

    vector&amp;lt;int&amp;gt; u;

    for(int i=0; i&amp;lt;N; i++)
        if(tf[i]) u.push_back(i+1);

    cout &amp;lt;&amp;lt; u.size() &amp;lt;&amp;lt; &quot;\n&quot;;

    for(int i=0; i&amp;lt;u.size(); i++) cout &amp;lt;&amp;lt; u[i] &amp;lt;&amp;lt; &quot; &quot;;
    cout &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 25456번 : 궁금한 시프트&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;FFT&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 2-SAT 문제가 아니고 FFT 문제인데 적을 곳이 없기도 하고 설명할 내용도 거의 없어서 여기에 끼워넣는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;백준 BOJ 1067번 : 이동&lt;/b&gt; 문제와 거의 구조가 비슷하고, 풀이 코드 또한 거의 유사하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 원리만 그대로 가져다가 풀어주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1669557979250&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

const double PI = acos(-1);
typedef complex&amp;lt;double&amp;gt; cpx;

void FFT(vector&amp;lt;cpx&amp;gt; &amp;amp;v, bool inv) {
    int S = v.size();

    for(int i=1, j=0; i&amp;lt;S; i++) {
        int bit = S/2;

        while(j &amp;gt;= bit) {
            j -= bit;
            bit /= 2;
        }
        j += bit;

        if(i &amp;lt; j) swap(v[i], v[j]);
    }

    for(int k=1; k&amp;lt;S; k*=2) {
        double angle = (inv ? PI/k : -PI/k);
        cpx w(cos(angle), sin(angle));

        for(int i=0; i&amp;lt;S; i+=k*2) {
            cpx z(1, 0);

            for(int j=0; j&amp;lt;k; j++) {
                cpx even = v[i+j];
                cpx odd = v[i+j+k];

                v[i+j] = even + z*odd;
                v[i+j+k] = even - z*odd;

                z *= w;
            }
        }
    }

    if(inv)
        for(int i=0; i&amp;lt;S; i++) v[i] /= S;
}

vector&amp;lt;int&amp;gt; mul(vector&amp;lt;int&amp;gt; &amp;amp;v, vector&amp;lt;int&amp;gt; &amp;amp;u) {
    vector&amp;lt;cpx&amp;gt; vc(v.begin(), v.end());
    vector&amp;lt;cpx&amp;gt; uc(u.begin(), u.end());

    int S = 2;
    while(S &amp;lt; v.size() + u.size()) S *= 2;

    vc.resize(S); FFT(vc, false);
    uc.resize(S); FFT(uc, false);

    for(int i=0; i&amp;lt;S; i++) vc[i] *= uc[i];
    FFT(vc, true);

    vector&amp;lt;int&amp;gt; w(S);
    for(int i=0; i&amp;lt;S; i++) w[i] = round(vc[i].real());

    return w;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    string a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

    int N = a.length();

    vector&amp;lt;int&amp;gt; v(N*2), u(N);
    
    for(int i=0; i&amp;lt;N; i++) v[i] = v[i+N] = a[i] - '0';
    for(int i=0; i&amp;lt;N; i++) u[N-1-i] = b[i] - '0';

    vector&amp;lt;int&amp;gt; w = mul(v, u);

    int ans = 0;
    for(int i=0; i&amp;lt;w.size(); i++) ans = max(ans, w[i]);

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/알고리즘 공부 내용 정리</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/643</guid>
      <comments>https://restudycafe.tistory.com/643#entry643comment</comments>
      <pubDate>Sun, 27 Nov 2022 23:13:05 +0900</pubDate>
    </item>
    <item>
      <title>빠른 MCMF 최소 비용 최대 유량 알고리즘 등 (+ 응용 문제 풀이)</title>
      <link>https://restudycafe.tistory.com/642</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;11월 말 백준에서 풀이한 문제들 중, 플래티넘 이상 난이도 문제들에서 다른 사람들이 잘 다루지 않는 내용들을 선별하여 정리해보려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 기간에 다룬 알고리즘은 MCMF(최소 비용 최대 유량)이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;낮은 난이도나 다른 사람들이 많이 푼 문제들은 이미 다 풀어서 플래티넘 난이도 중에서도 어려운 것만 남았고, 그에 대한 풀이를 다룬 사람들이 별로 없어서 간략하게나마 적어본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어디까지나 스스로 공부, 잊어버렸을 때 나중에 다시 참고하기 위한 목적이지만 혹시나 검색 유입으로 보는 사람이 있다면 도움이 될 수 있으면 좋겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 14424번 : 두부장수 장홍준 3&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Diamond V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;MCMF (최소 비용 최대 유량)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 이 문제는 이전에 백준 BOJ 11111번 : 두부장수 장홍준 2 문제에 대한 풀이를 다룬 적이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 이 문제에서는 N, M의 제한이 50에서 200으로 늘어났고, 11111번 문제의 풀이 코드를 제출하면 일반적으로는 시간 초과에 걸리게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제를 풀기 위해서는 기존 MCMF 알고리즘에 대해 최적화가 조금 더 이루어진 코드가 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #eeeeee; color: #000000;&quot;&gt;Dinic 알고리즘과 같이 유량을 갱신함과 동시에 새로운 DAG를 O(V+E) 시간에 갱신하는 최적화된 MCMF에 대한 구현을 찾을 수 있어 이를 참고하여 풀이하였다. (jhnah917님의 블로그에서 참고하였다. &lt;/span&gt;&lt;span style=&quot;background-color: #eeeeee; color: #000000;&quot;&gt;처음부터 다시 작성했고 구조가 많이 다르긴 하지만 사실 본질은&lt;span style=&quot;background-color: #eeeeee; color: #000000;&quot;&gt;&amp;nbsp;거의 똑같이 구현되긴 했다.)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #eeeeee; color: #000000;&quot;&gt;정형화시킨 코드는 팀노트(?)라고 부르기는 애매하지만 아무튼 오른쪽 카테고리의 &quot;알고리즘 구현 코드 모음&quot;의 MCMF 파트에 정리되어 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1669555425341&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct sm {
	// referred to the jhnah917's implementation (purpose of study)

    struct se { int num, cap, sco, ord; };
    vector&amp;lt;vector&amp;lt;se&amp;gt;&amp;gt; adj;

    void edge(int a, int b, int c, int d) {
        adj[a].push_back({b, c, d, adj[b].size()});
        adj[b].push_back({a, 0, -d, adj[a].size()-1});
    }

    int sour, sink;
    vector&amp;lt;int&amp;gt; tco, idx;
    vector&amp;lt;bool&amp;gt; chk;

    int dfs(int x, int flo) {
        chk[x] = true;

        if(x == sink) return flo;

        for(; idx[x] &amp;lt; adj[x].size(); idx[x]++) {
            se &amp;amp;ad = adj[x][idx[x]];

            if(chk[ad.num] || tco[x] + ad.sco != tco[ad.num] || ad.cap == 0) continue;

            int ret = dfs(ad.num, min(flo, ad.cap));

            if(ret == 0) continue;

            ad.cap -= ret;
            adj[ad.num][ad.ord].cap += ret;

            return ret;
        }

        return 0;
    }

    pair&amp;lt;int, int&amp;gt; mcmf(int sour_, int sink_) {
        sour = sour_, sink = sink_;

        int minc = 0, maxf = 0;

        tco.resize(adj.size(), INT_MAX);
        tco[sour] = 0;

        queue&amp;lt;int&amp;gt; q;
        q.push(sour);

        vector&amp;lt;bool&amp;gt; inq(adj.size());
        inq[sour] = true;

        while(!q.empty()) {
            int x = q.front();
            q.pop(); inq[x] = false;

            for(int i=0; i&amp;lt;adj[x].size(); i++) {
                int y = adj[x][i].num;
                int cap = adj[x][i].cap;
                int sco = adj[x][i].sco;

                if(cap &amp;lt;= 0 || tco[x] + sco &amp;gt;= tco[y]) continue;

                tco[y] = tco[x] + sco;

                if(inq[y]) continue;

                q.push(y);
                inq[y] = true;
            }
        }

        while(true) {
            chk.clear(); chk.resize(adj.size());
            idx.clear(); idx.resize(adj.size());

            while(true) {
                int cur = dfs(sour, INT_MAX);
                if(cur == 0) break;

                minc += tco[sink] * cur;
                maxf += cur;

                chk.clear(); chk.resize(adj.size());
            }

            int Min = INT_MAX;

            for(int i=0; i&amp;lt;adj.size(); i++) {
                if(!chk[i]) continue;

                for(int j=0; j&amp;lt;adj[i].size(); j++) {
                    int x = adj[i][j].num;
                    int cap = adj[i][j].cap;
                    int sco = adj[i][j].sco;

                    if(cap &amp;gt; 0 &amp;amp;&amp;amp; !chk[x]) Min = min(Min, tco[i] + sco - tco[x]);
                }
            }

            if(Min == INT_MAX) break;

            for(int i=0; i&amp;lt;adj.size(); i++)
                if(!chk[i]) tco[i] += Min;
        }

        return {minc, maxf};
    }
};

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    vector&amp;lt;vector&amp;lt;char&amp;gt;&amp;gt; v(N+1, vector&amp;lt;char&amp;gt;(M+1));

    for(int i=1; i&amp;lt;=N; i++)
        for(int j=1; j&amp;lt;=M; j++) cin &amp;gt;&amp;gt; v[i][j];

    sm f;

    f.adj.resize(N*M + 3);

    int sour = N*M + 1, sink = N*M + 2;

    int cvt[6][6] = {{10, 8, 7, 5, 0, 1},
                      {8, 6, 4, 3, 0, 1},
                      {7, 4, 3, 2, 0, 1},
                      {5, 3, 2, 2, 0, 1},
                      {0, 0, 0, 0, 0, 0},
                      {1, 1, 1, 1, 0, 0}};

    for(int i=1; i&amp;lt;=N; i++)
        for(int j=1; j&amp;lt;=M; j++) {
            if((i + j) % 2 == 0) {
                f.edge(sour, (i-1)*M + j, 1, 0);
                f.edge((i-1)*M + j, sink, 1, 0);

                int di[4] = {1, -1, 0, 0};
                int dj[4] = {0, 0, 1, -1};

                for(int k=0; k&amp;lt;4; k++) {
                    int ni = i + di[k];
                    int nj = j + dj[k];

                    if(ni &amp;lt; 1 || nj &amp;lt; 1 || ni &amp;gt; N || nj &amp;gt; M) continue;

                    f.edge((i-1)*M + j, (ni-1)*M + nj, 1, -cvt[v[i][j]-'A'][v[ni][nj]-'A']);
                }
            }
            else f.edge((i-1)*M + j, sink, 1, 0);
        }


    pair&amp;lt;int, int&amp;gt; mcmf = f.mcmf(sour, sink);

    int minc = mcmf.first;
    int maxf = mcmf.second;

    cout &amp;lt;&amp;lt; -minc &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 5892번 : Landscaping&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;MCMF (최소 비용 최대 유량)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 애초에 내가 질문 글을 올렸으니 그 이미지를 첨부한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;835&quot; data-origin-height=&quot;797&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wkXOc/btrSa77WmlY/xYjEstS8OU9609EaKCfr11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wkXOc/btrSa77WmlY/xYjEstS8OU9609EaKCfr11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wkXOc/btrSa77WmlY/xYjEstS8OU9609EaKCfr11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwkXOc%2FbtrSa77WmlY%2FxYjEstS8OU9609EaKCfr11%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;835&quot; height=&quot;797&quot; data-origin-width=&quot;835&quot; data-origin-height=&quot;797&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 문제인데 아무튼 정석 풀이는 DP이고, 그래서 난이도가 &lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;Platinum V&lt;/span&gt;&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;질문 글을 올리고 다음 날 답변이 달렸는데 이 문제를 유일하게 MCMF로 푸신 djs100201님이 풀이를 거의 떠먹여주시다시피 알려주셔서 구현해볼 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MCMF로 푸는 방법은 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;545&quot; data-origin-height=&quot;497&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/euWB4J/btrSa6HTCys/DbyNyY0cC8PXiuR7m5zvW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/euWB4J/btrSa6HTCys/DbyNyY0cC8PXiuR7m5zvW1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/euWB4J/btrSa6HTCys/DbyNyY0cC8PXiuR7m5zvW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeuWB4J%2FbtrSa6HTCys%2FDbyNyY0cC8PXiuR7m5zvW1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;545&quot; height=&quot;497&quot; data-origin-width=&quot;545&quot; data-origin-height=&quot;497&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;X와 Y를 처리할 노드를 하나 만들어서 마음껏 처리할 수 있도록 해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 A_i값들의 합 asum과 B_i값들의 합 bsum을 구해 만약 asum이 더 크다면, (asum - bsum) x Y만큼 답에 더해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반대의 경우에는 (bsum - asum) x X만큼 답에 더해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대충 생각했을 때는 X, Y 값이 Z보다 매우 작을 경우 예외가 발생할 것 같기도 한데, 따로 연결한 노드 하나에서 그러한 예외가 모두 처리되기 때문에, 우선 최대한 싸게 이동을 시킨 뒤 마지막에 추가 또는 제거를 해도 답에 영향을 주지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1669556069152&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct se {
    int num, ord, cap, sco;

    se(int num, int ord, int cap, int sco) : num(num), ord(ord), cap(cap), sco(sco) {}
};

vector&amp;lt;vector&amp;lt;se&amp;gt;&amp;gt; adj;
int maxf, minc;

void edge(int a, int b, int c, int d) {
    adj[a].emplace_back(b, adj[b].size(), c, d);
    adj[b].emplace_back(a, adj[a].size()-1, 0, -d);
}

void mcmf(int sour, int sink) {
    while(true) {
        vector&amp;lt;int&amp;gt; pre(adj.size(), -1), idx(adj.size(), -1);

        vector&amp;lt;int&amp;gt; tco(adj.size(), INT_MAX);
        tco[sour] = 0;

        queue&amp;lt;int&amp;gt; q;
        q.push(sour);

        vector&amp;lt;bool&amp;gt; inq(adj.size());
        inq[sour] = true;

        while(!q.empty()) {
            int x = q.front();
            q.pop();
            inq[x] = false;

            for(int i=0; i&amp;lt;adj[x].size(); i++) {
                int y = adj[x][i].num;
                int cap = adj[x][i].cap;
                int sco = adj[x][i].sco;

                if(cap &amp;lt;= 0 || tco[x] + sco &amp;gt;= tco[y]) continue;

                tco[y] = tco[x] + sco;
                pre[y] = x;
                idx[y] = i;

                if(inq[y]) continue;

                q.push(y);
                inq[y] = true;
            }
        }
        if(pre[sink] == -1) break;

        int sfl = INT_MAX;

        for(int i=sink; i!=sour; i=pre[i]) {
            int a = pre[i], b = idx[i];

            sfl = min(sfl, adj[a][b].cap);
        }

        for(int i=sink; i!=sour; i=pre[i]) {
            int a = pre[i], b = idx[i];

            adj[a][b].cap -= sfl;
            adj[i][adj[a][b].ord].cap += sfl;

            minc += sfl * adj[a][b].sco;
        }

        maxf += sfl;
    }
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, X, Y, Z; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; X &amp;gt;&amp;gt; Y &amp;gt;&amp;gt; Z;

    vector&amp;lt;int&amp;gt; v(N+1), u(N+1);
    int vsum = 0, usum = 0;

    for(int i=1; i&amp;lt;=N; i++) {
        cin &amp;gt;&amp;gt; v[i] &amp;gt;&amp;gt; u[i];

        vsum += v[i];
        usum += u[i];
    }

    adj.clear();
    adj.resize(N+4);

    int ext = N+1, sour = N+2, sink = N+3;

    for(int i=1; i&amp;lt;=N; i++) {
        edge(sour, i, v[i], 0);
        edge(i, sink, u[i], 0);

        edge(i, ext, INT_MAX, Y);
        edge(ext, i, INT_MAX, X);

        for(int j=1; j&amp;lt;=N; j++)
            if(i != j) edge(i, j, INT_MAX, abs(i-j)*Z);
    }

    int ans = 0;

    if(vsum &amp;gt; usum) ans += (vsum - usum) * Y;
    else if(vsum &amp;lt; usum) ans += (usum - vsum) * X;

    maxf = 0, minc = 0;

    mcmf(sour, sink);

    ans += minc;

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #eeeeee; color: #000000;&quot;&gt;백준 BOJ 17506번 : 주때의 자소서 쓰기&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #eeeeee; color: #000000;&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum II&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #eeeeee; color: #000000;&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;MCMF (최소 비용 최대 유량)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 이렇게 접근했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1353&quot; data-origin-height=&quot;965&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5c0tU/btrSf9cAg5c/tnsrgPDYylXL1lNJPoBCCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5c0tU/btrSf9cAg5c/tnsrgPDYylXL1lNJPoBCCk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5c0tU/btrSf9cAg5c/tnsrgPDYylXL1lNJPoBCCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5c0tU%2FbtrSf9cAg5c%2FtnsrgPDYylXL1lNJPoBCCk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;369&quot; height=&quot;263&quot; data-origin-width=&quot;1353&quot; data-origin-height=&quot;965&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 A, B, C 각각에 최소 하나 이상의 소재는 배정을 받아야 한다는 조건이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 처리해주기 위해서는 아주 낮은 비용으로 유량을 1씩 흘려줘서 무조건 흘러주게 하는 방법이 있는데, 그렇게 하기 위해서는 그래프를 좌우로 뒤집어주어야 한다. (A, B, C가 왼쪽으로 오도록)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1373&quot; data-origin-height=&quot;1005&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dRSTNf/btrScbIZRkT/zImjxlHbOt1SG1HmiiG6g1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dRSTNf/btrScbIZRkT/zImjxlHbOt1SG1HmiiG6g1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dRSTNf/btrScbIZRkT/zImjxlHbOt1SG1HmiiG6g1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdRSTNf%2FbtrScbIZRkT%2FzImjxlHbOt1SG1HmiiG6g1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;585&quot; height=&quot;428&quot; data-origin-width=&quot;1373&quot; data-origin-height=&quot;1005&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 이렇게 되고, -1e7 정도의 값으로 pri 노드에 유량을 흘려주면, 최소 비용으로 유량이 흐르므로 pri 노드의 3의 유량은 무조건 A, B, C 각각에 1씩 흐르게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이들이 우선적으로 배정이 되고, 그 다음 나머지 유량들이 흐르므로 원하는 결과를 얻을 수 있게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막에는 3e7을 더해준 뒤 마이너스 붙여서 답을 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1669556823171&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct MCMF {
	// referred to the jhnah917's implementation (purpose of study)

    struct se { int num, cap, sco, ord; };
    vector&amp;lt;vector&amp;lt;se&amp;gt;&amp;gt; adj;

    void edge(int a, int b, int c, int d) {
        adj[a].push_back({b, c, d, adj[b].size()});
        adj[b].push_back({a, 0, -d, adj[a].size()-1});
    }

    int sour, sink;
    vector&amp;lt;int&amp;gt; tco, idx;
    vector&amp;lt;bool&amp;gt; chk;

    int dfs(int x, int flo) {
        chk[x] = true;

        if(x == sink) return flo;

        for(; idx[x] &amp;lt; adj[x].size(); idx[x]++) {
            se &amp;amp;ad = adj[x][idx[x]];

            if(chk[ad.num] || tco[x] + ad.sco != tco[ad.num] || ad.cap == 0) continue;

            int ret = dfs(ad.num, min(flo, ad.cap));

            if(ret == 0) continue;

            ad.cap -= ret;
            adj[ad.num][ad.ord].cap += ret;

            return ret;
        }

        return 0;
    }

    pair&amp;lt;int, int&amp;gt; mcmf(int sour_, int sink_) {
        sour = sour_, sink = sink_;

        int minc = 0, maxf = 0;

        tco.resize(adj.size(), INT_MAX);
        tco[sour] = 0;

        queue&amp;lt;int&amp;gt; q;
        q.push(sour);

        vector&amp;lt;bool&amp;gt; inq(adj.size());
        inq[sour] = true;

        while(!q.empty()) {
            int x = q.front();
            q.pop(); inq[x] = false;

            for(int i=0; i&amp;lt;adj[x].size(); i++) {
                int y = adj[x][i].num;
                int cap = adj[x][i].cap;
                int sco = adj[x][i].sco;

                if(cap &amp;lt;= 0 || tco[x] + sco &amp;gt;= tco[y]) continue;

                tco[y] = tco[x] + sco;

                if(inq[y]) continue;

                q.push(y);
                inq[y] = true;
            }
        }

        while(true) {
            chk.clear(); chk.resize(adj.size());
            idx.clear(); idx.resize(adj.size());

            while(true) {
                int cur = dfs(sour, INT_MAX);
                if(cur == 0) break;

                minc += tco[sink] * cur;
                maxf += cur;

                chk.clear(); chk.resize(adj.size());
            }

            int Min = INT_MAX;

            for(int i=0; i&amp;lt;adj.size(); i++) {
                if(!chk[i]) continue;

                for(int j=0; j&amp;lt;adj[i].size(); j++) {
                    int x = adj[i][j].num;
                    int cap = adj[i][j].cap;
                    int sco = adj[i][j].sco;

                    if(cap &amp;gt; 0 &amp;amp;&amp;amp; !chk[x]) Min = min(Min, tco[i] + sco - tco[x]);
                }
            }

            if(Min == INT_MAX) break;

            for(int i=0; i&amp;lt;adj.size(); i++)
                if(!chk[i]) tco[i] += Min;
        }

        return {minc, maxf};
    }
};

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    MCMF f;

    int S = N+8;
    f.adj.resize(S);

    int sour = S-1, sink = S-2, pri = S-3, ext = S-4;

    f.edge(sour, pri, 3, -1e7);
    f.edge(sour, ext, INT_MAX, 0);

    for(int i=1; i&amp;lt;=3; i++) {
        int x; cin &amp;gt;&amp;gt; x;

        f.edge(sour, N+i, x-1, 0);
        f.edge(pri, N+i, 1, 0);
    }

    for(int i=1; i&amp;lt;=N; i++) {
        for(int j=1; j&amp;lt;=3; j++) {
            int x; cin &amp;gt;&amp;gt; x;

            f.edge(N+j, i, 1, -x);
        }

        f.edge(ext, i, 1, 0);
        f.edge(i, sink, 1, 0);
    }

    pair&amp;lt;int, int&amp;gt; mcmf = f.mcmf(sour, sink);

    int minc = mcmf.first;
    int maxf = mcmf.second;

    int ans = -(minc + 1e7 * 3);

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 7154번 : Job Postings&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;MCMF (최소 비용 최대 유량)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 어렵지는 않은데 누가 질문글을 올렸고 구글링해봐도 풀이가 없길래 간단하게 그래프와 풀이 코드만 첨부한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1473&quot; data-origin-height=&quot;1085&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d5m1rq/btrScawAF7q/Gkh9y7OA6OWxRT0XIKb5vk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d5m1rq/btrScawAF7q/Gkh9y7OA6OWxRT0XIKb5vk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d5m1rq/btrScawAF7q/Gkh9y7OA6OWxRT0XIKb5vk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd5m1rq%2FbtrScawAF7q%2FGkh9y7OA6OWxRT0XIKb5vk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;437&quot; height=&quot;322&quot; data-origin-width=&quot;1473&quot; data-origin-height=&quot;1085&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1669556920907&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct se {
    int num, cap, sco, ord;

    se(int num, int cap, int sco, int ord) : num(num), cap(cap), sco(sco), ord(ord) {}
};

vector&amp;lt;vector&amp;lt;se&amp;gt;&amp;gt; adj;
int maxf, minc;

void edge(int a, int b, int c, int d) {
    adj[a].emplace_back(b, c, d, adj[b].size());
    adj[b].emplace_back(a, 0, -d, adj[a].size()-1);
}

void mcmf(int sour, int sink) {
    while(true) {
        vector&amp;lt;int&amp;gt; pre(adj.size(), -1), idx(adj.size(), -1);

        vector&amp;lt;int&amp;gt; tco(adj.size(), INT_MAX);
        tco[sour] = 0;

        queue&amp;lt;int&amp;gt; q;
        q.push(sour);

        vector&amp;lt;bool&amp;gt; inq(adj.size());
        inq[sour] = true;

        while(!q.empty()) {
            int x = q.front();
            q.pop();
            inq[x] = false;

            for(int i=0; i&amp;lt;adj[x].size(); i++) {
                int y = adj[x][i].num;
                int cap = adj[x][i].cap;
                int sco = adj[x][i].sco;

                if(cap &amp;lt;= 0 || tco[x] + sco &amp;gt;= tco[y]) continue;

                tco[y] = tco[x] + sco;
                pre[y] = x;
                idx[y] = i;

                if(inq[y]) continue;

                q.push(y);
                inq[y] = true;
            }
        }
        if(pre[sink] == -1) break;

        int sfl = INT_MAX;

        for(int i=sink; i!=sour; i=pre[i]) {
            int a = pre[i], b = idx[i];

            sfl = min(sfl, adj[a][b].cap);
        }

        for(int i=sink; i!=sour; i=pre[i]) {
            int a = pre[i], b = idx[i];

            adj[a][b].cap -= sfl;
            adj[i][adj[a][b].ord].cap += sfl;

            minc += sfl * adj[a][b].sco;
        }

        maxf += sfl;
    }
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    while(true) {
        int N, M; cin &amp;gt;&amp;gt; M &amp;gt;&amp;gt; N;
        if(N == 0 &amp;amp;&amp;amp; M == 0) break;

        adj.clear();
        adj.resize(N+M+3);

        int sour = N+M+1, sink = N+M+2;

        for(int i=1; i&amp;lt;=M; i++) {
            int x; cin &amp;gt;&amp;gt; x;

            edge(N+i, sink, x, 0);
        }

        for(int i=1; i&amp;lt;=N; i++) {
            edge(sour, i, 1, 0);

            int a; cin &amp;gt;&amp;gt; a;

            for(int j=0; j&amp;lt;4; j++) {
                int b; cin &amp;gt;&amp;gt; b;

                edge(i, N+b+1, 1, -(a*4-j));
            }
        }

        maxf = minc = 0;

        mcmf(sour, sink);

        cout &amp;lt;&amp;lt; -minc &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 1650번 : 지민이의 테러 Season II&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt; Platinum III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;MCMF (최소 비용 최대 유량)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 길을 두 번 지나가지 않되 1번 노드에서 N번 노드 사이를 왕복하는 최소 비용을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간선의 방향이 양방향인 경우 반대로 갈 때 마이너스 비용 처리를 하기 애매하므로 노드를 분할하여 in, out을 따로 처리해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이 문제에서는 왕복 비용을 구하라고 하였으므로 유량을 2만큼 흘려주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1669557037624&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct se {
    int num, cap, sco, ord;

    se(int num, int cap, int sco, int ord) : num(num), cap(cap), sco(sco), ord(ord) {}
};

vector&amp;lt;vector&amp;lt;se&amp;gt;&amp;gt; adj;
int maxf, minc;

void edge(int a, int b, int c, int d) {
    adj[a].emplace_back(b, c, d, adj[b].size());
    adj[b].emplace_back(a, 0, -d, adj[a].size()-1);
}

void mcmf(int sour, int sink) {
    while(true) {
        vector&amp;lt;int&amp;gt; pre(adj.size(), -1), idx(adj.size(), -1);

        vector&amp;lt;int&amp;gt; tco(adj.size(), INT_MAX);
        tco[sour] = 0;

        queue&amp;lt;int&amp;gt; q;
        q.push(sour);

        vector&amp;lt;bool&amp;gt; inq(adj.size());
        inq[sour] = true;

        while(!q.empty()) {
            int x = q.front();
            q.pop();
            inq[x] = false;

            for(int i=0; i&amp;lt;adj[x].size(); i++) {
                int y = adj[x][i].num;
                int cap = adj[x][i].cap;
                int sco = adj[x][i].sco;

                if(cap &amp;lt;= 0 || tco[x] + sco &amp;gt;= tco[y]) continue;

                tco[y] = tco[x] + sco;
                pre[y] = x;
                idx[y] = i;

                if(inq[y]) continue;

                q.push(y);
                inq[y] = true;
            }
        }
        if(pre[sink] == -1) break;

        int sfl = INT_MAX;

        for(int i=sink; i!=sour; i=pre[i]) {
            int a = pre[i], b = idx[i];

            sfl = min(sfl, adj[a][b].cap);
        }

        for(int i=sink; i!=sour; i=pre[i]) {
            int a = pre[i], b = idx[i];

            adj[a][b].cap -= sfl;
            adj[i][adj[a][b].ord].cap += sfl;

            minc += sfl * adj[a][b].sco;
        }

        maxf += sfl;
    }
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    adj.clear();
    adj.resize(N*2 + 3);

    int sour = N*2 + 1, sink = N*2 + 2;

    edge(sour, 1, 2, 0);
    edge(N+N, sink, 2, 0);

    for(int i=1; i&amp;lt;=N; i++) edge(i, N+i, INT_MAX, 0);

    while(M--) {
        int a, b, c; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b &amp;gt;&amp;gt; c;

        edge(N+a, b, 1, c);
        edge(N+b, a, 1 ,c);
    }

    maxf = 0, minc = 0;

    mcmf(sour, sink);

    cout &amp;lt;&amp;lt; minc &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/알고리즘 공부 내용 정리</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/642</guid>
      <comments>https://restudycafe.tistory.com/642#entry642comment</comments>
      <pubDate>Sun, 27 Nov 2022 22:56:14 +0900</pubDate>
    </item>
    <item>
      <title>11월 알고리즘 공부 : 최소 외접원/구, 가장 가까운 두 점, 번사이드 보조정리 등</title>
      <link>https://restudycafe.tistory.com/639</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;최근 글 작성 빈도가 현저히 낮아졌는데, 바쁘다거나 그런 이유보다는 2022년 막바지로 갈수록 의욕이 떨어져간다는 표현이 맞는 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래도 아직 백준에서 2022년 푼 문제 수 랭킹 1위를 유지하고 있기 때문에 최소한 유종의 미라도 거두기 위해 연말까지는 열심히 풀어보려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무튼 11월 중순동안 공부한 내용들을 나중에 스스로 참고할 수 있도록 정리해보려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 2626번 : 헬기착륙장&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Diamond V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;최소 외접원&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2차원 좌표 평면 상의 N개의 점이 주어질 때 이들을 모두 포함하는 가장 작은 원의 중심과 반지름을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세 점을 지나는 원이 반드시 존재함을 이용하여 풀이하는 문제이다. (여담으로, 타원의 경우 최대 다섯 개의 점을 지나는 타원이 반드시 존재한다. 어떤 점을 잡아도 무조건 지나는 원이 있으려면 3개의 점이 최대이고, 구의 경우에는 4개이다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 3중 for문을 이용하여 가장 바깥쪽의 세 점을 지나는 원을 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세 점을 지나는 원의 중심 좌표에 대한 식은 문제에서 알려준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3중 for문이므로 시간 복잡도가 O(N^3)처럼 보이지만, 실제로는 어떤 점이 현재 구한 원을 벗어나야만 for문 내부의 코드가 작동하므로 실질적인 작동 시간은 O(N)에 가깝다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1669118214027&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct p { double x, y; };

double dis(p a, p b) {
    return sqrt(pow(a.x - b.x, 2) + pow(a.y - b.y, 2));
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    cout &amp;lt;&amp;lt; fixed;
    cout.precision(3);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;p&amp;gt; v(N);
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i].x &amp;gt;&amp;gt; v[i].y;

    p cen = {0, 0};
    double r = 0;

    for(int i=0; i&amp;lt;N; i++) {
        if(dis(cen, v[i]) &amp;lt;= r) continue;

        cen = v[i], r = 0;

        for(int j=0; j&amp;lt;i; j++) {
            if(dis(cen, v[j]) &amp;lt;= r) continue;

            cen = {(v[i].x + v[j].x) / 2, (v[i].y + v[j].y) / 2};
            r = dis(cen, v[i]);

            for(int k=0; k&amp;lt;j; k++) {
                if(dis(cen, v[k]) &amp;lt;= r) continue;

                cen.x = ((pow(v[j].x, 2) - pow(v[k].x, 2) + pow(v[j].y, 2) - pow(v[k].y, 2)) * (v[i].y - v[j].y)
                         - (pow(v[j].x, 2) - pow(v[i].x, 2) + pow(v[j].y, 2) - pow(v[i].y, 2)) * (v[k].y - v[j].y))
                         / ((v[i].x - v[j].x) * (v[k].y - v[j].y) * 2 - (v[k].x - v[j].x) * (v[i].y - v[j].y) * 2);
                cen.y = ((pow(v[j].y, 2) - pow(v[k].y, 2) + pow(v[j].x, 2) - pow(v[k].x, 2)) * (v[i].x - v[j].x)
                         - (pow(v[j].y, 2) - pow(v[i].y, 2) + pow(v[j].x, 2) - pow(v[i].x, 2)) * (v[k].x - v[j].x))
                         / ((v[i]. y- v[j].y) * (v[k].x - v[j].x) * 2 - (v[k].y - v[j].y) * (v[i].x - v[j].x) * 2);
                r = dis(cen, v[i]);
            }
        }
    }

    if(abs(cen.x) &amp;lt; 1e-4) cen.x = 0;
    if(abs(cen.y) &amp;lt; 1e-4) cen.y = 0;

    cout &amp;lt;&amp;lt; cen.x &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; cen.y &amp;lt;&amp;lt; &quot;\n&quot;;
    cout &amp;lt;&amp;lt; r &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제를 풀이하면 거의 비슷한 코드로 다음의 문제들을 풀 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백준 BOJ 2389번 : 세상의 중심에서... (&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum I&lt;/b&gt;&lt;/span&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백준 BOJ 13708번 : 모든 점을 포함하는 원 (&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum I&lt;/b&gt;&lt;/span&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백준 BOJ 21182번 : Weird Flecks, But OK (&lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;Platinum I&lt;/span&gt;&lt;/b&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백준 BOJ 10517번 : Radar Coverage (&lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold III&lt;/b&gt;&lt;/span&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;풀이 코드는 거의 비슷하므로 생략한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 11930번 : Smallest Enclosing Sphere&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Diamond V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;최소 외접원, 3차원 기하학&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3차원 좌표 상의 N개의 점이 주어질 때, 이 점들을 모두 포함하는 가장 작은 구의 반지름을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 문제의 풀이를 확장시키면 풀이할 수 있지만, 식의 구현이 매우 복잡하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 나와 같은 방식으로 휴리스틱 없이 풀이한 사람은 1명인 것으로 확인된다. (실행 시간이 0ms에 가까워야 함)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;식으로 이 문제를 풀기 위해서는 다음의 2가지 식이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1) 3차원 좌표 상에서 3개의 점을 지나는 원의 중심을 구하는 공식&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2) 3차원 좌표 상에서 4개의 점을 지나는 구의 중심을 구하는 공식&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이들은 모두 행렬 식을 이용하여 풀이할 수 있는데, 역행렬을 구하는 과정이나 행렬 곱을 구하는 과정이 매우 복잡해서 자세한 설명은 아래의 코드로 대체한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1669118605077&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct p { double x, y, z; };

double dis(p a, p b) {
    return sqrt(pow(a.x - b.x, 2) + pow(a.y - b.y, 2) + pow(a.z - b.z, 2));
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    cout &amp;lt;&amp;lt; fixed;
    cout.precision(2);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;p&amp;gt; v(N);
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i].x &amp;gt;&amp;gt; v[i].y &amp;gt;&amp;gt; v[i].z;

    p cen = {0, 0, 0};
    double r = 0;

    for(int i=0; i&amp;lt;N; i++) {
        if(dis(cen, v[i]) &amp;lt;= r) continue;

        cen = v[i], r = 0;

        for(int j=0; j&amp;lt;i; j++) {
            if(dis(cen, v[j]) &amp;lt;= r) continue;

            cen = {(v[i].x + v[j].x) / 2, (v[i].y + v[j].y) / 2, (v[i].z + v[j].z) / 2};
            r = dis(cen, v[i]);

            for(int k=0; k&amp;lt;j; k++) {
                if(dis(cen, v[k]) &amp;lt;= r) continue;

                double ax = v[i].x, ay = v[i].y, az = v[i].z;
                double bx = v[j].x, by = v[j].y, bz = v[j].z;
                double cx = v[k].x, cy = v[k].y, cz = v[k].z;

                double Cx = bx - ax, Cy = by - ay, Cz = bz - az;
                double Bx = cx - ax, By = cy - ay, Bz = cz - az;

                double B2 = ax*ax - cx*cx + ay*ay - cy*cy + az*az - cz*cz;
                double C2 = ax*ax - bx*bx + ay*ay - by*by + az*az - bz*bz;

                double CByz = Cy*Bz - Cz*By;
                double CBxz = Cx*Bz - Cz*Bx;
                double CBxy = Cx*By - Cy*Bx;

                double zz1 = - (Bz - Cz*Bx/Cx) / (By - Cy*Bx/Cx);
                double z01 = - (B2 - Bx/Cx*C2) / ((By - Cy*Bx/Cx) * 2);
                double zz2 = - (zz1*Cy + Cz) / Cx;
                double z02 = - (z01*Cy*2 + C2) / (Cx * 2);

                cen.z = - ((z02 - ax) * CByz - (z01 - ay) * CBxz - az * CBxy) / (zz2 * CByz - zz1 * CBxz + CBxy);
                cen.x = zz2 * cen.z + z02;
                cen.y = zz1 * cen.z + z01;

                r = dis(cen, v[i]);

                for(int l=0; l&amp;lt;k; l++) {
                    if(dis(cen, v[l]) &amp;lt;= r) continue;

                    double x1 = v[i].x, x2 = v[j].x, x3 = v[k].x, x4 = v[l].x;
                    double y1 = v[i].y, y2 = v[j].y, y3 = v[k].y, y4 = v[l].y;
                    double z1 = v[i].z, z2 = v[j].z, z3 = v[k].z, z4 = v[l].z;

                    double a11 = x2 - x1, a12 = y2 - y1, a13 = z2 - z1;
                    double a21 = x3 - x2, a22 = y3 - y2, a23 = z3 - z2;
                    double a31 = x4 - x1, a32 = y4 - y1, a33 = z4 - z1;

                    double det = a11 * (a22*a33 - a23*a32) - a12 * (a21*a33 - a23*a31) + a13 * (a21*a32 - a22*a31);

                    double c11 = a22*a33 - a32*a23, c12 = - (a12*a33 - a32*a13), c13 = a12*a23 - a22*a13;
                    double c21 = - (a21*a33 - a31*a23), c22 = a11*a33 - a31*a13, c23 = - (a11*a23 - a21*a13);
                    double c31 = a21*a32 - a31*a22, c32 = - (a11*a32 - a31*a12), c33 = a11*a22 - a21*a12;

                    double xx = x2*x2 - x1*x1 + y2*y2 - y1*y1 + z2*z2 - z1*z1;
                    double yy = x3*x3 - x2*x2 + y3*y3 - y2*y2 + z3*z3 - z2*z2;
                    double zz = x4*x4 - x1*x1 + y4*y4 - y1*y1 + z4*z4 - z1*z1;

                    cen.x = (c11*xx + c12*yy + c13*zz) / (det * 2);
                    cen.y = (c21*xx + c22*yy + c23*zz) / (det * 2);
                    cen.z = (c31*xx + c32*yy + c33*zz) / (det * 2);

                    r = dis(cen, v[i]);
                }
            }
        }
    }

    if(abs(cen.x) &amp;lt; 1e-4) cen.x = 0;
    if(abs(cen.y) &amp;lt; 1e-4) cen.y = 0;
    if(abs(cen.z) &amp;lt; 1e-4) cen.z = 0;

    // cout &amp;lt;&amp;lt; cen.x &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; cen.y &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; cen.z &amp;lt;&amp;lt; &quot;\n&quot;;
    cout &amp;lt;&amp;lt; r &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 6567번 : Let it Bead&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;조합론, 번사이드 보조정리&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 원형으로 배치된 구슬을 M개의 색을 이용하여 칠하고, 이들을 회전시키거나 뒤집었을 때 같은 색 배치인 것은 동일한 것으로 판단할 때 가능한 조합이 몇 개인지 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;번사이드 보조정리에 대해서 배울 수 있는 연습 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원리는 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 원형의 구슬의 조합으로 가능한 것을 하나 만들었다고 할 때, 예를 들어 이것이 RBRB로 2칸 회전시켰을 때마다 동일한 형태가 나온다면 중복을 제거하지 않고 2번 count 되도록 해준 뒤, 마지막에 N = 4로 나누어 한 번만 count 되도록 하는 것이다. (RBRB에서 2번, BRBR에서 2번 count 되고 이것을 4로 나누면 RBRB 1개만 count가 되므로 옳게 세어졌다는 것을 알 수 있다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 이 문제는 여기서 끝이 아니라 뒤집었을 때 같은 것도 동일한 것으로 판단하므로, 뒤집은 형태까지 모두 고려해주되 2N번씩 count 되도록 해주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 뒤집었을 때 동일한 것 = 대칭이어야 하므로 대칭 형태인 것들의 개수를 세어주어서 총 count에 이것들까지 중복이 되도록 더해준 뒤 2N으로 나누어 답을 구해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1669118931398&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    while(true) {
        int N, M; cin &amp;gt;&amp;gt; M &amp;gt;&amp;gt; N;
        if(N == 0 &amp;amp;&amp;amp; M == 0) break;

        int ans = 0;

        for(int i=1; i&amp;lt;=N; i++) ans += pow(M, __gcd(N, i));

        if(N % 2 == 0) ans += (N / 2) * (pow(M, N/2) + pow(M, N/2 + 1));
        else ans += N * pow(M, (N + 1)/2);

        ans /= (N * 2);

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 2261번 : 가장 가까운 두 점&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;기하학, 분할 정복&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2차원 좌표 평면 위에 N개의 점이 주어질 때, 가장 가까운 두 점 사이의 거리의 제곱을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 먼 두 점은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;컨벡스 헐 + 회전하는 캘리퍼스&lt;/u&gt;로 구현이 가능하지만 가장 가까운 두 점은 어떻게 구할까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방법은 바로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;분할 정복&lt;/b&gt;을 이용하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;점들을 x 좌표를 기준으로 오름차순 정렬을 해준 뒤, 가운데 점을 기준으로 분할 정복을 통해 최소 거리의 점을 찾는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분할 정복을 통해 구하는 과정에서 왼쪽 그룹의 점과 오른쪽 그룹의 점을 각각 선택하여 얻어지는 거리는 확인하지 않았으므로, 현재까지 구한 최소 거리보다 중점으로부터 가까운 점들을 모두 벡터에 넣고 가능한 조합들을 모두 검사해본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 시간 초과를 방지하기 위해 벡터에 저장된 점들을 y 좌표를 기준으로 정렬한 뒤 이중 for문을 돌리는 과정에서 두 점의 y 좌표의 차이가 Min 값 이상이 되면 즉시 break문을 사용하여 불필요한 값의 비교가 최소화되도록 해주어야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1669118884114&quot; class=&quot;arduino&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { int x, y; };

bool cmpx(s a, s b) {
    if(a.x != b.x) return a.x &amp;lt; b.x;
    else return a.y &amp;lt; b.y;
}

bool cmpy(s a, s b) {
    if(a.y != b.y) return a.y &amp;lt; b.y;
    else return a.x &amp;lt; b.x;
}

int dis(s a, s b) {
    return pow(a.x - b.x, 2) + pow(a.y - b.y, 2);
}

vector&amp;lt;s&amp;gt; v;

int f(int l, int r) {
    if(l == r) return LLONG_MAX;
    if(l+1 == r) return dis(v[l], v[r]);

    int m = (l + r) / 2;
    int Min = min({dis(v[l], v[r]), f(l, m), f(m+1, r)});

    vector&amp;lt;s&amp;gt; u;
    int cen = v[m].x;

    for(int i=l; i&amp;lt;=r; i++)
        if(pow(v[i].x - cen, 2) &amp;lt; Min) u.push_back(v[i]);

    sort(u.begin(), u.end(), cmpy);

    for(int i=0; i&amp;lt;u.size(); i++)
        for(int j=i+1; j&amp;lt;u.size(); j++) {
            if(pow(u[i].y - u[j].y, 2) &amp;gt;= Min) break;

            if(pow(u[i].x - u[j].x, 2) &amp;lt; Min) Min = min(Min, dis(u[i], u[j]));
        }

    return Min;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    v.resize(N);
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i].x &amp;gt;&amp;gt; v[i].y;

    sort(v.begin(), v.end(), cmpx);

    int ans = f(0, N-1);

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 26003번 : Lowest Latency&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;b&gt;난이도 정보 없음&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : 정보 없음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;0 &amp;le; x, y, z &amp;lt; 10^9인 점이 무작위로 10^5개가 주어질 때, 가장 가까운 두 점 사이의 거리를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 상황에서는 어떻게 구해야할까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 &lt;b&gt;가장 가까운 두 점&lt;/b&gt; 문제와 같은 방법으로 분할 정복을 이용한 구현이 가능하겠지만, 3차원 상의 점들이기 때문에 구현이 훨씬 복잡할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제에서는 점의 위치가 무작위로 주어진다는 점에 주목해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 간단한 해결책은 점의 위치가 무작위라는 것은 이들이 상당히 균일한 분포를 가지고 있고, 따라서 대략적으로 계산했을 때 넉넉잡아 답이 최소한 10^6은 넘어간다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 점들을 x 좌표를 기준으로 정렬했을 때 v[i]와 v[i+1] ~ v[i+100] 정도만 비교해줘도 확률적으로 그 안에는 무조건 답이 있음을 유추할 수 있다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 O(N log N) 시간에 정렬을 수행하고, O(100 N) 시간에 탐색을 수행할 수 있으므로 충분히 짧은 시간에 답을 구할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1669118108509&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { int x, y, z; };

bool cmp(s a, s b) {
    return a.x &amp;lt; b.x;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    cout &amp;lt;&amp;lt; fixed;
    cout.precision(6);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;s&amp;gt; v(N);
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i].x &amp;gt;&amp;gt; v[i].y &amp;gt;&amp;gt; v[i].z;

    sort(v.begin(), v.end(), cmp);

    double ans = DBL_MAX;

    for(int i=0; i&amp;lt;N; i++)
        for(int j=i+1; j&amp;lt;i+100 &amp;amp;&amp;amp; j&amp;lt;N; j++) {
            double dis = sqrt(pow(v[i].x - v[j].x, 2) + pow(v[i].y - v[j].y, 2) + pow(v[i].z - v[j].z, 2));

            ans = min(ans, dis);
        }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 22940번 : 선형 연립 방정식&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;가우스 소거법&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가우스 소거법을 이용하여 N차 선형 연립 방정식의 해를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비교적 최근 문제로 출제되었고 전에 가우스 소거법을 구현할 줄 몰라서 풀지 못했던 문제가 기억나서 생각난 김에 구현해보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같이 구현하면 거의 최소한의 코드로 가우스 소거법을 구현할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1669117234326&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    int M = N + 1;

    vector&amp;lt;vector&amp;lt;double&amp;gt;&amp;gt; v(N, vector&amp;lt;double&amp;gt;(M));

    for(int i=0; i&amp;lt;N; i++)
        for(int j=0; j&amp;lt;M; j++) cin &amp;gt;&amp;gt; v[i][j];

    for(int i=0; i&amp;lt;N; i++) {
        for(int j=0; j&amp;lt;N; j++) {
            double d = v[i][i], c = v[j][i] / v[i][i];

            for(int k=0; k&amp;lt;M; k++) {
                if(j == i) v[j][k] /= d;
                else v[j][k] -= c * v[i][k];
            }
        }
    }

    for(int i=0; i&amp;lt;N; i++) cout &amp;lt;&amp;lt; v[i].back() &amp;lt;&amp;lt; &quot; &quot;;
    cout &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 아직 주어진 행렬에 대해 RREF와 같은 꼴을 만들도록 하는 코드는 구현하지 못했는데, 가까운 시일 내에 구현해볼 수 있도록 노력해보겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 26017번 : Guessing Game&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;2-SAT&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7일동안 각각 d_i개의 대회가 열리고, N명의 사람들이 매일 각 대회들 중 하나를 골라 승패 여부를 예상할 때, 마지막 2일동안의 승패 예상만 가지고 N명의 사람들을 모두 이길 수 있는지 여부를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 사람들은 1개 이하로 맞추고, 마지막 줄에 주어진 2개의 예측이 모두 맞으면 조건을 만족한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2-SAT를 이용해 문제를 풀이하기 위해 N명 각각에 대해 7C2개의 조합을 가지고 하나가 맞으면 다른 하나가 틀리게 되도록 N x 7C2개의 조건식을 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동시에 마지막 줄에 주어진 2개의 예측이 a, b라고 할 때 이들 또한 2-SAT 식의 절에 들어가야 하므로 ~a &amp;rarr; a와 ~b &amp;rarr; b 식을 추가해준 뒤 2-SAT를 돌려주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1669120333388&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj, scc;
vector&amp;lt;int&amp;gt; nnum, cnum;
int ncnt = 0, ccnt = 0;

stack&amp;lt;int&amp;gt; s;
vector&amp;lt;bool&amp;gt; ch;

int dfs(int x) {
    nnum[x] = ++ncnt;
    s.push(x);

    int tmp = nnum[x];

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(nnum[y] == 0) tmp = min(tmp, dfs(y));
        else if(!ch[y]) tmp = min(tmp, nnum[y]);
    }

    if(tmp == nnum[x]) {
        vector&amp;lt;int&amp;gt; v;
        ccnt++;

        while(true) {
            int y = s.top();
            s.pop();

            v.push_back(y);

            ch[y] = true;
            cnum[y] = ccnt;

            if(y == x) break;
        }

        sort(v.begin(), v.end());

        scc.push_back(v);
    }

    return tmp;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;int&amp;gt; add(8);
    for(int i=1; i&amp;lt;=7; i++) {
        cin &amp;gt;&amp;gt; add[i];

        add[i] += add[i-1];
    }

    int M = add[7];

    adj.resize(M*2);

    for(int i=0; i&amp;lt;N; i++) {
        vector&amp;lt;int&amp;gt; v(7);
        for(int j=0; j&amp;lt;7; j++) {
            cin &amp;gt;&amp;gt; v[j];

            if(v[j] &amp;gt; 0) v[j] += add[j];
            else v[j] -= add[j];
        }

        for(int j=0; j&amp;lt;7; j++)
            for(int k=j+1; k&amp;lt;7; k++) {
                int a = -v[j], b = -v[k];

                if(a &amp;lt; 0) a = (-a)*2 - 2;
                else a = a*2 - 1;

                if(b &amp;lt; 0) b = (-b)*2 - 2;
                else b = b*2 - 1;

                int na, nb;

                if(a % 2 == 0) na = a + 1;
                else na = a - 1;

                if(b % 2 == 0) nb = b + 1;
                else nb = b - 1;

                adj[na].push_back(b);
                adj[nb].push_back(a);
            }
    }

    for(int i=0; i&amp;lt;2; i++) {
        int x; cin &amp;gt;&amp;gt; x;

        if(x &amp;gt; 0) x += add[5+i];
        else x -= add[5+i];

        if(x &amp;lt; 0) x = (-x)*2 - 2;
        else x = x*2 - 1;

        int nx;

        if(x % 2 == 0) nx = x + 1;
        else nx = x - 1;

        adj[nx].push_back(x);
    }

    nnum.resize(M*2);
    cnum.resize(M*2);
    ch.resize(M*2);

    for(int i=0; i&amp;lt;M*2; i++)
        if(nnum[i] == 0) dfs(i);

    bool check = true;

    for(int i=0; i&amp;lt;M; i++) {
        if(cnum[i*2] == cnum[i*2 + 1]) {
            check = false;
            break;
        }
    }

    if(check) cout &amp;lt;&amp;lt; &quot;possible\n&quot;;
    else cout &amp;lt;&amp;lt; &quot;impossible\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 26012번 : Breeding Bugs&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭, 에라토스테네스의 체&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 수가 주어질 때 어떤 두 수를 골라도 그 합이 소수가 되지 않도록 하는 집합의 최대 크기를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2를 제외한 모든 소수는 홀수이므로, 수들을 짝수와 홀수로 나누어 최대 독립 집합의 크기를 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최대 독립 집합의 크기 = N - 최대 매칭이라는 공식이 있으므로, 이분 매칭으로 문제를 풀어주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예외 처리로 2가 나오지 않으려면 1이 1개 이하로 집합에 포함되면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소수 판별을 빨리 하기 위해 에라토스테네스의 체를 이용해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1669120491996&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int Max = 2e7;

    vector&amp;lt;bool&amp;gt; p(Max, true);
    p[1] = false;

    for(int i=2; i*i&amp;lt;Max; i++)
        for(int j=2; i*j&amp;lt;Max; j++) p[i*j] = false;


    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;int&amp;gt; v, u;
    bool one = false;

    while(N--) {
        int x; cin &amp;gt;&amp;gt; x;

        if(x == 1) {
            if(!one) {
                v.push_back(x);
                one = true;
            }

            continue;
        }

        if(x % 2 == 1) v.push_back(x);
        else u.push_back(x);
    }

    adj.resize(v.size());

    for(int i=0; i&amp;lt;v.size(); i++)
        for(int j=0; j&amp;lt;u.size(); j++)
            if(p[v[i] + u[j]]) adj[i].push_back(j);

    l.resize(v.size(), -1);
    r.resize(u.size(), -1);

    int match = 0;

    for(int i=0; i&amp;lt;v.size(); i++) {
        vis.clear();
        vis.resize(v.size());

        if(f(i)) match++;
    }

    int ans = v.size() + u.size() - match;

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 26050번 : 수열의 합 2&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt; Gold I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;정수론&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주어진 N에 대해 N의 모든 약수 d1, ... , dk가 있을 때 a_n = (-1)^d1 + (-1)^d2 + ... + (-1)^dk라고 한다면 주어지는 s, t에 대해 a_s + ... + a_t의 값을 구하는 문제이다. 이 때 s, t &amp;le; 10^14이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;s, t 범위가 크므로 O(sqrt(N)) 풀이를 찾아야 하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 a_1 + ... + a_N을 구하는 함수 f(N)를 구현하고 답은 f(t) - f(s-1)로 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;약수 dk가 나타나는 횟수는 N / dk를 내림한 값이므로, (-1)^dk &amp;times; (N / dk)의 시그마 값을 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 이렇게 풀면 O(N) 시간에 풀이가 가능한데, 시간을 더 줄여야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발견할 수 있는 성질은 N의 약수는 O(sqrt(N)) 시간에 구할 수 있을 정도로 적으므로, N / dk 값들의 종류도 O(sqrt(N)) 시간에 구할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 각 N / dk 값이 변화하는 구간을 찾고, 이 구간의 길이만큼의 값을 한번에 구해줄 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자세한 내용은 아래의 풀이 코드를 참고하면 쉬울 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1669119439621&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

int f(int N) {
    vector&amp;lt;int&amp;gt; v, u;

    for(int i=1; i*i&amp;lt;=N; i++) {
        if(v.empty() || N/i != v.back()) {
            v.push_back(i);

            if(i != N/i) u.push_back(N/i);
        }
    }

    for(int i=u.size()-1; i&amp;gt;=0; i--) v.push_back(u[i]);

    int sum = (-1) * N;

    for(int i=1; i&amp;lt;v.size(); i++) {
        if((v[i] - v[i-1]) % 2 == 0) continue;

        sum += (v[i] % 2 == 0 ? 1 : -1) * (N / v[i]);
    }

    return sum;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

    int ans = f(b) - f(a-1);

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 13738번 : Ghostbusters 2&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;2-SAT, 이분 탐색&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 지점이 주어지고, 각 지점에서 상하 또는 좌우로 길이 x인 선분을 발사하여 같은 축에 있는 선분이 서로 겹치지 않게 하기 위한 x의 최댓값을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;x를 임의로 정하고 서로 겹치는 것이 발생할 수 있는지를 검사하는 것은 가능하므로, 이분 탐색으로 접근하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 x에 대해서는 선분을 가로로 발사하면 true, 세로로 발사하면 false라고 생각하면 2-SAT 문제가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 같은 가로축에 위치한 두 지점에 대해, 두 지점의 거리가 2x 이하이면 지점 a에서의 선분을 좌우로 선택했을 때 지점 b에서의 선분은 반드시 상하로 선택해야 하므로 a &amp;rarr; not b가 되고, 마찬가지로 not b &amp;rarr; a가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 식으로 여러 개의 절을 세워서 2-SAT 문제로 풀어주어 만약 가능한 상태가 존재한다면 l = m+1로, 그렇지 않다면 r = m-1로 설정하며 가능한 최댓값을 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1669207026797&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj, scc;
vector&amp;lt;int&amp;gt; nnum, cnum;
int ncnt = 0, ccnt = 0;

stack&amp;lt;int&amp;gt; s;
vector&amp;lt;bool&amp;gt; ch;

int dfs(int x) {
    nnum[x] = ++ncnt;
    s.push(x);

    int tmp = nnum[x];

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(nnum[y] == 0) tmp = min(tmp, dfs(y));
        else if(!ch[y]) tmp = min(tmp, nnum[y]);
    }

    if(tmp == nnum[x]) {
        vector&amp;lt;int&amp;gt; v;
        ccnt++;

        while(true) {
            int y = s.top();
            s.pop();

            v.push_back(y);

            ch[y] = true;
            cnum[y] = ccnt;

            if(y == x) break;
        }

        sort(v.begin(), v.end());

        scc.push_back(v);
    }

    return tmp;
}

struct st { int x, y; };

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;st&amp;gt; v(N+1);
    for(int i=1; i&amp;lt;=N; i++) cin &amp;gt;&amp;gt; v[i].x &amp;gt;&amp;gt; v[i].y;

    int l = 0, r = INT_MAX, ans = 0;

    while(l &amp;lt;= r) {
        int m = (l + r) / 2;

        adj.clear(); adj.resize(N*2);

        for(int i=1; i&amp;lt;=N; i++)
            for(int j=i+1; j&amp;lt;=N; j++) {
                int a = i, b = j;

                if(a &amp;lt; 0) a = (-a)*2 - 2;
                else a = a*2 - 1;

                if(b &amp;lt; 0) b = (-b)*2 - 2;
                else b = b*2 - 1;

                int na, nb;

                if(a % 2 == 0) na = a + 1;
                else na = a - 1;

                if(b % 2 == 0) nb = b + 1;
                else nb = b - 1;

                if(v[i].x == v[j].x &amp;amp;&amp;amp; abs(v[i].y - v[j].y) &amp;lt;= m*2) {
                    adj[a].push_back(nb);
                    adj[b].push_back(na);
                }
                if(v[i].y == v[j].y &amp;amp;&amp;amp; abs(v[i].x - v[j].x) &amp;lt;= m*2) {
                    adj[na].push_back(b);
                    adj[nb].push_back(a);
                }
            }

        nnum.clear(); nnum.resize(N*2);
        cnum.clear(); cnum.resize(N*2);
        ch.clear();   ch.resize(N*2);

        scc.clear();
        ncnt = ccnt = 0;

        for(int i=0; i&amp;lt;N*2; i++)
            if(nnum[i] == 0) dfs(i);

        bool check = true;

        for(int i=0; i&amp;lt;N; i++) {
            if(cnum[i*2] == cnum[i*2 + 1]) {
                check = false;
                break;
            }
        }

        if(check) {
            ans = max(ans, m);
            l = m + 1;
        }
        else r = m - 1;
    }

    if(ans &amp;lt; INT_MAX) cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    else cout &amp;lt;&amp;lt; &quot;UNLIMITED\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/알고리즘 공부 내용 정리</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/639</guid>
      <comments>https://restudycafe.tistory.com/639#entry639comment</comments>
      <pubDate>Tue, 22 Nov 2022 21:34:59 +0900</pubDate>
    </item>
    <item>
      <title>백준 BOJ 17030번 : Cow Dating 풀이 (Diamond V, 투 포인터)</title>
      <link>https://restudycafe.tistory.com/638</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 17030번 : Cow Dating&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Diamond V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;투 포인터, 누적 합&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 선택받을 확률 p_i가 주어질 때 (실제 입력은 p_i의 10^6배를 한 값들로 주어진다.) 연속한 구간 p_l ~ p_r을 선택하여 그들 중 하나에게만 선택이 될 확률의 최댓값을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;3168&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QTbDu/btrQ4a4uwTc/xD86Zy6jtKzM7NnazxK4Q1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QTbDu/btrQ4a4uwTc/xD86Zy6jtKzM7NnazxK4Q1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QTbDu/btrQ4a4uwTc/xD86Zy6jtKzM7NnazxK4Q1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQTbDu%2FbtrQ4a4uwTc%2FxD86Zy6jtKzM7NnazxK4Q1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;703&quot; height=&quot;1392&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;3168&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구간을 잡고 관계식을 찾는 것이 핵심이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구간 [l, r]에서의 확률이 이미 있을 때, 어떤 조건에서 구간을 늘렸을 때 확률이 늘어나는지 계산해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구간 [l, r]에서 하나에게만 선택받을 확률 &lt;b&gt;f(l, r)&lt;/b&gt;은 위의 식처럼 나타낼 수 있고, 거기에 항을 하나 추가하여 &lt;u&gt;f(l, r+1)을 관계식으로 구할 수 있다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 &lt;span style=&quot;color: #ee2323;&quot;&gt;f(l, r+1) &amp;gt; f(l, r)&lt;/span&gt;일 조건을 찾아주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;식을 풀어보면 &lt;span style=&quot;color: #ee2323;&quot;&gt;p_i / (1 - p_i)의 구간 합이 1보다 작을 때와 동치&lt;/span&gt;이므로, [1, 1]에서 시작하여 해당 조건을 만족할 때 오른쪽 구간을 늘리고 그렇지 않으면 왼쪽 구간을 줄이는 식으로&lt;b&gt; 투 포인터&lt;/b&gt; 알고리즘을 통해 &lt;span style=&quot;color: #ee2323;&quot;&gt;O(N)&lt;/span&gt;에 풀이할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제에서는 O(N^2) 풀이를 허용하지 않으므로 (N &amp;le; 60,000)&lt;b&gt;&amp;nbsp;누적 합&lt;/b&gt;을 이용하여 &lt;u&gt;O(1) 시간에 위의 시그마 식을 구해줄 수 있도록&lt;/u&gt; 해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 구간 곱을 사용하면 구간이 넓어질 때 값이 0에 수렴하여 오차가 발생하므로 앞에 곱해지는 곱은 매 반복문마다 갱신해서 구해주는 방식을 사용해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1668238386450&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;double&amp;gt; v(N+1);

    for(int i=1; i&amp;lt;=N; i++) {
        cin &amp;gt;&amp;gt; v[i];

        v[i] *= 1e-6;
    }

    vector&amp;lt;double&amp;gt; u(N+1);

    for(int i=1; i&amp;lt;=N; i++)
        u[i] = u[i-1] + v[i] / (1 - v[i]);

    int i = 1, j = 1;
    double p = 1 - v[1], ans = 0;

    while(j &amp;lt;= N) {
        ans = max(ans, p * (u[j] - u[i-1]));

        if(u[j] - u[i-1] &amp;lt; 1) {
            j++;
            p *= (1 - v[j]);
        }
        else {
            i++;
            p /= (1 - v[i-1]);
        }
    }

    ans = (int)(ans * 1e6);

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/알고리즘 공부 내용 정리</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/638</guid>
      <comments>https://restudycafe.tistory.com/638#entry638comment</comments>
      <pubDate>Sat, 12 Nov 2022 16:58:17 +0900</pubDate>
    </item>
    <item>
      <title>백준 BOJ 24486번 : Counting Haybales 풀이 (Diamond II, DP)</title>
      <link>https://restudycafe.tistory.com/637</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 24486번 : Counting Haybales&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Diamond II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;DP&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 자연수가 주어지고, 크기 차이가 1인 인접한 두 수를 서로 swap할 수 있다고 할 때, 만들 수 있는 서로 다른 수열의 개수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제의 풀이는 USACO 사이트를 참고하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;1660&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMgKau/btrQTDUjhOK/yxlj5DdIVLurKf7gHsDieK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMgKau/btrQTDUjhOK/yxlj5DdIVLurKf7gHsDieK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMgKau/btrQTDUjhOK/yxlj5DdIVLurKf7gHsDieK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMgKau%2FbtrQTDUjhOK%2Fyxlj5DdIVLurKf7gHsDieK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;642&quot; height=&quot;666&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;1660&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 관찰을 통해 알 수 있는 사실은 &lt;span style=&quot;color: #ee2323;&quot;&gt;홀짝성이 같은 수들끼리는 순서가 바뀔 수 없다&lt;/span&gt;는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(이것은 오직 크기 차이가 1인 인접한 두 수만 교환이 가능하므로, 홀짝성이 같은 = 크기가 2 이상 차이나는 수는 서로 위치가 바뀔 수 없기 때문이다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 정석적인 풀이는 이 사실을 이용하여 그래프의 단방향 간선들을 만들 수 있으므로, &lt;b&gt;위상 정렬&lt;/b&gt;로 푸는 풀이로 보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무튼 홀짝성을 활용하여 문제를 풀이하기 위해, &lt;b&gt;dp[i][j]&lt;/b&gt;를 &lt;u&gt;수열의 앞 부분 i+j개의 수들 중 i개의 짝수와 j개의 홀수가 나타나는 길이 i+j인 서로 다른 수열의 개수&lt;/u&gt;라고 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 점화식을 만들기 위해 다음의 값들을 구해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;olp[j']&lt;/b&gt; : inversion 불가능한 i'번째 홀수와 j'번째 짝수(홀수가 왼쪽)가 있을 때, j'번째 짝수에 대해 가능한 odd's leftmost position&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;elp[j']&lt;/b&gt; : inversion 불가능한 i'번째 짝수와 j'번째 홀수(짝수가 왼쪽)가 있을 때, j'번째 홀수에 대해 가능한 even's leftmost position&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(inversion 불가능하다는 것은 두 수의 차가 1보다 큰 경우를 의미한다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N이 5,000 이하로 충분히 작으므로 O(N^2) 시간에 이중 for문으로 모든 쌍들에 대해 검사하여 olp와 elp 값들을 구할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;olp[j']&amp;nbsp;&lt;/b&gt;:&amp;nbsp;j'번째(=&amp;nbsp;num[j])&amp;nbsp;짝수&amp;nbsp;왼쪽에&amp;nbsp;있을&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;홀수의&amp;nbsp;가장&amp;nbsp;왼쪽&amp;nbsp;번호&amp;nbsp;(max로&amp;nbsp;갱신하면서&amp;nbsp;왼쪽&amp;nbsp;임계값을&amp;nbsp;오른쪽으로&amp;nbsp;좁혀나감)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;elp[j']&lt;/b&gt;&amp;nbsp;:&amp;nbsp;j'번째(=&amp;nbsp;num[j])&amp;nbsp;홀수&amp;nbsp;왼쪽에&amp;nbsp;있을&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;짝수의&amp;nbsp;가장&amp;nbsp;왼쪽&amp;nbsp;번호&amp;nbsp;(max로&amp;nbsp;갱신하면서&amp;nbsp;왼쪽&amp;nbsp;임계값을&amp;nbsp;오른쪽으로&amp;nbsp;좁혀나감)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 모든 이제 모든 i번째 짝수와 j번째 홀수에 대해 O(even x odd) 시간에 dp값을 계산해주면 된다. (even : 짝수 개수, odd : 홀수 개수)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;j번째 홀수가 olp[i] = i번째 짝수 왼쪽에 있을 수 있는 홀수의 가장 왼쪽 번호와 같거나 오른쪽에 있는 경우, &lt;span style=&quot;color: #ee2323;&quot;&gt;dp[i][j] += dp[i-1][j]&lt;/span&gt;가 성립한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반대로 i번째 짝수가 elp[j] = j번째 홀수 왼쪽에 있을 수 있는 짝수의 가장 왼쪽 번호와 같거나 오른쪽에 있는 경우에도, &lt;span style=&quot;color: #ee2323;&quot;&gt;dp[i][j] += dp[i][j-1]&lt;/span&gt;이 성립한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최종적으로는 &lt;span style=&quot;color: #ee2323;&quot;&gt;dp[even][odd]&lt;/span&gt;가 답이 된다. (even : 짝수 개수, odd : 홀수 개수)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1668070285712&quot; class=&quot;arduino&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    while(T--) {
        int N; cin &amp;gt;&amp;gt; N;

        vector&amp;lt;int&amp;gt; v(N), num(N);
        int e = 0, o = 0;

        for(int i=0; i&amp;lt;N; i++) {
            cin &amp;gt;&amp;gt; v[i];

            if(v[i] % 2 == 0) num[i] = ++e;
            else if(v[i] % 2 == 1) num[i] = ++o;
        }

        vector&amp;lt;int&amp;gt; olp(e+1), elp(o+1);

        for(int i=0; i&amp;lt;N; i++)
            for(int j=i+1; j&amp;lt;N; j++)
                if(v[i] % 2 != v[j] % 2 &amp;amp;&amp;amp; abs(v[i] - v[j]) &amp;gt; 1) {
                    if(v[j] % 2 == 0) olp[num[j]] = max(olp[num[j]], num[i]);
                    if(v[j] % 2 == 1) elp[num[j]] = max(elp[num[j]], num[i]);
                }

        vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; dp(e+1, vector&amp;lt;int&amp;gt;(o+1));
        dp[0][0] = 1;

        int mod = 1e9 + 7;

        for(int i=0; i&amp;lt;=e; i++)
            for(int j=0; j&amp;lt;=o; j++) {
                if(i &amp;gt; 0 &amp;amp;&amp;amp; j &amp;gt;= olp[i]) dp[i][j] = (dp[i][j] + dp[i-1][j]) % mod;
                if(j &amp;gt; 0 &amp;amp;&amp;amp; i &amp;gt;= elp[j]) dp[i][j] = (dp[i][j] + dp[i][j-1]) % mod;
            }

        int ans = dp[e][o];

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여담으로 FFT를 활용하면 이 문제를 O(N log N) 시간에도 풀이가 가능하다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/알고리즘 공부 내용 정리</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/637</guid>
      <comments>https://restudycafe.tistory.com/637#entry637comment</comments>
      <pubDate>Thu, 10 Nov 2022 17:07:02 +0900</pubDate>
    </item>
    <item>
      <title>백준 BOJ 10058번 : 센서 네트워크 풀이 (Ruby V, 이분 매칭)</title>
      <link>https://restudycafe.tistory.com/636</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;백준에서 3600문제 넘게 풀면서 &lt;span style=&quot;color: #ff005f;&quot;&gt;루비&lt;/span&gt; 난이도 문제를 처음으로 푼 기념으로 이 문제만 별개의 포스트로 정리해본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무려 월드 파이널 문제이며 그 해 문제 중에서도 solved.ac 기준으로 난이도가 가장 높은 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 10058번 : 센서 네트워크&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #ff005f;&quot;&gt;&lt;b&gt;Ruby V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;기하학, 이분 매칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2차원 좌표 평면 상에 N개의 점이 주어질 때, 어떤 두 점의 거리도 M 이하가 되게 하는 점들의 집합의 최대 크기와 그 때의 점들의 번호 목록을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 naive하게 생각할 수 있는 풀이는 각 점을 집합에 포함시키거나 시키지 않은 뒤 해당 집합에서 가장 먼 두 점 사이의 거리가 M 이하라면 집합의 최대 크기를 비교하여 갱신해주는 방식이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때의 시간 복잡도는 최소 O(2^N) 이상이 되고, 당연히 시간 초과이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N &amp;le; 100으로 N의 제한이 매우 크지 않음에 주목하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;임의의 두 점이 집합에서 가장 먼 두 점이라고 먼저 가정한 뒤, 이 집합에 포함될 수 있는 점들을 탐색한다면, 이중 for문 내에서 별개의 이중 for문을 더 돌려서 O(N^4)가 되어도 충분히 돌아간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 두 점을 잡고 이 두 점 사이의 거리가 집합에서 가장 먼 두 점이 되도록 집합을 완성하여 답을 구해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1401&quot; data-origin-height=&quot;897&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Z3Faw/btrPQdCwt0M/PJ9xMKtv2lElNpZyapiOTk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Z3Faw/btrPQdCwt0M/PJ9xMKtv2lElNpZyapiOTk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Z3Faw/btrPQdCwt0M/PJ9xMKtv2lElNpZyapiOTk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZ3Faw%2FbtrPQdCwt0M%2FPJ9xMKtv2lElNpZyapiOTk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;730&quot; height=&quot;467&quot; data-origin-width=&quot;1401&quot; data-origin-height=&quot;897&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결정한 두 점이 A, B이고, 두 점 사이의 거리가 r &amp;le; M이라고 할 때, 점 A에서 반지름 r인 원과 점 B에서 반지름 r인 원을 그려서 그 교집합에 포함되는 점들이 집합에 포함될 수 있는 점들의 후보가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 두 원의 교점 사이의 거리가 r보다 크므로 반례가 존재하게 된다. (예를 들면 위의 그림에서 선분 xy가 반례가 된다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 핵심 아이디어가 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;교집합에 포함되는 점들을 선분 AB를 기준으로 위에 위치하는 점들과 아래에 위치하는 점들로 나눠보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로는 두 점 A, B가 x축에 평행하게 위치하지 않으므로, &lt;u&gt;ccw를 사용하여 ccw 값을 0을 기준으로 두 부분&lt;/u&gt;으로 나누어 선분 AB를 기준으로 양쪽에 위치하는 점들로 나누면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 같은 그룹에 속한 점들 사이의 거리는 반드시 r 이하이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 점들을 위 그룹과 아래 그룹으로 나누어 거리가 r보다 큰 위의 점과 아래의 점 사이를 간선으로 연결하여 이분 그래프를 만들어주고, 여기서 이분 매칭을 수행하여 최대 매칭 수만큼 점들에서 빼주면 그것이 최종적인 집합의 크기가 된다. 즉, 이제 이 집합에는 어떤 두 점 사이의 거리도 r 이하가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 집합의 크기는 위 그룹 + 아래 그룹 - 최대 매칭 수임을 알 수 있는데 일부 점을 뺄 때 어떤 점을 빼야하냐는 것이다. (최종적으로 점들의 번호를 구해야하므로)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &lt;b&gt;최소 정점 커버&lt;/b&gt;에 대한 다음의 정리를 사용해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이분 그래프에서 왼쪽 정점 그룹을 L, 오른쪽 정점 그룹을 R이라고 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이분 매칭이 수행된 이분 그래프에서 &lt;b&gt;alternating path&lt;/b&gt;란 &lt;u&gt;최대 매칭에 포함되는 간선과 포함되지 않는 간선을 번갈아가며 선택하면서 이동하는 경로&lt;/u&gt;를 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;L의 최대 매칭에 포함되지 않는 점들에서 시작하여 alternating path로 도달할 수 있는 모든 정점들의 집합을 X라고 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 &lt;b&gt;최소 정점 커버 = (L - X) &amp;cup; (R &amp;cap; X)&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 풀이가 끝났다. 풀이를 요약하면 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 가능한 모든 두 점의 조합들 중 거리가 M 이하인 두 점에 대해 다음을 반복한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 두 점을 기준으로 반지름이 두 점 사이의 거리인 원을 그려 교집합에 들어오는 점들을, 두 점을 잇는 선분을 기준으로 ccw값의 부호에 따라 두 그룹으로 나눈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 거리가 r 이상인 점들 사이에 간선을 연결해주고 이분 매칭을 수행하여 최소로 지워야 하는 점의 수를 구하고, 집합의 크기를 구한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 집합의 원소를 구하기 위해 최소 정점 커버에 대한 정리를 사용하여 구해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 이렇게 구한 집합들 중에서 크기가 가장 큰 것을 답으로 출력해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것을 코드로 구현하면 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 정답 처리를 받은 풀이 코드이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1667000803546&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { double x, y; int n; };

double dis(s a, s b) {
    return sqrt(pow(a.x - b.x, 2) + pow(a.y - b.y, 2));
}

double ccw(s a, s b, s c) {
    return a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y);
}

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; ll, rr;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(rr[y] == -1 || (!vis[rr[y]] &amp;amp;&amp;amp; f(rr[y]))) {
            ll[x] = y, rr[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;
    double M; cin &amp;gt;&amp;gt; M;

    vector&amp;lt;s&amp;gt; v(N);
    for(int i=0; i&amp;lt;N; i++) {
        cin &amp;gt;&amp;gt; v[i].x &amp;gt;&amp;gt; v[i].y;

        v[i].n = i+1;
    }

    vector&amp;lt;int&amp;gt; ans;
    ans.push_back(1);

    for(int i=0; i&amp;lt;N; i++)
        for(int j=i+1; j&amp;lt;N; j++) {
            double r = dis(v[i], v[j]);

            if(r &amp;gt; M) continue;

            vector&amp;lt;s&amp;gt; u, w;

            for(int k=0; k&amp;lt;N; k++) {
                if(dis(v[i], v[k]) &amp;gt; r || dis(v[j], v[k]) &amp;gt; r) continue;

                if(ccw(v[i], v[j], v[k]) &amp;gt;= 0) u.push_back(v[k]);
                else w.push_back(v[k]);
            }

            adj.clear();
            adj.resize(u.size());

            for(int k=0; k&amp;lt;u.size(); k++)
                for(int l=0; l&amp;lt;w.size(); l++)
                    if(dis(u[k], w[l]) &amp;gt; r) adj[k].push_back(l);

            ll.clear(); ll.resize(u.size(), -1);
            rr.clear(); rr.resize(w.size(), -1);

            int match = 0;

            for(int k=0; k&amp;lt;u.size(); k++) {
                vis.clear();
                vis.resize(u.size());

                if(f(k)) match++;
            }

            if(u.size() + w.size() - match &amp;lt;= ans.size()) continue;

            vector&amp;lt;bool&amp;gt; lvis(u.size()), rvis(w.size());

            for(int k=0; k&amp;lt;u.size(); k++) {
                if(ll[k] != -1 || lvis[k]) continue;

                lvis[k] = true;

                queue&amp;lt;pair&amp;lt;bool, int&amp;gt;&amp;gt; q;
                q.push({true, k});

                while(!q.empty()) {
                    bool isLeft = q.front().first;
                    int x = q.front().second;
                    q.pop();

                    if(isLeft) {
                        for(int l=0; l&amp;lt;adj[x].size(); l++) {
                            int y = adj[x][l];

                            if(ll[x] != y &amp;amp;&amp;amp; !rvis[y]) {
                                rvis[y] = true;
                                q.push({false, y});
                            }
                        }
                    }
                    else {
                        for(int l=0; l&amp;lt;u.size(); l++) {
                            int y = l;

                            if(lvis[y]) continue;
                            if(count(adj[y].begin(), adj[y].end(), x) == 0) continue;

                            for(int m=0; m&amp;lt;adj[y].size(); m++) {
                                if(adj[y][m] != x) continue;

                                if(rr[x] == y) {
                                    lvis[y] = true;
                                    q.push({true, y});
                                }
                            }
                        }
                    }
                }
            }

            ans.clear();

            for(int k=0; k&amp;lt;u.size(); k++)
                if(lvis[k]) ans.push_back(u[k].n);

            for(int k=0; k&amp;lt;w.size(); k++)
                if(!rvis[k]) ans.push_back(w[k].n);
        }

    cout &amp;lt;&amp;lt; ans.size() &amp;lt;&amp;lt; &quot;\n&quot;;

    for(int i=0; i&amp;lt;ans.size(); i++) cout &amp;lt;&amp;lt; ans[i] &amp;lt;&amp;lt; &quot; &quot;;
    cout &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/알고리즘 공부 내용 정리</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/636</guid>
      <comments>https://restudycafe.tistory.com/636#entry636comment</comments>
      <pubDate>Sat, 29 Oct 2022 10:16:46 +0900</pubDate>
    </item>
    <item>
      <title>이분 매칭 알고리즘 어려운 문제들 풀이 (Platinum II ~ Diamond)</title>
      <link>https://restudycafe.tistory.com/635</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 3419번 : Racing Car Trail&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Diamond III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N x M 크기의 배열이 주어지고, X가 없는 칸에서만 이동이 가능하다고 할 때, Alice와 Bob이 번갈아가면서 지나온 칸은 다시 이동하지 않도록 칸을 이동시키면서 상대가 더 이상 이동하지 못하도록 최선의 전략으로 이동시킨다고 할 때, 각 칸에서 시작할 때 누가 이기는지를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;격자 그래프는 이분 그래프이므로 이분 매칭 알고리즘으로 최대 매칭을 구한 뒤, 시작점 v를 포함하지 않는 최대 매칭이 존재한다면 Bob이 항상 이길 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐하면 그러한 매칭이 존재하는 경우 Alice는 어떻게 이동해도 최대 매칭에 포함되는 정점으로 이동하게 되고, Bob은 그 격자점과 매칭되어있는 점을 따라서만 이동시키면 되기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 그러한 매칭이 존재하지 않는 경우 이번에는 Alice가 격자점과 매칭되어있는 점을 따라서 이동시키면 승리하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N x M 모든 격자에 대해 그래프 연결을 다시 수행한 뒤 이분 매칭을 각각 돌리면 시간 초과가 발생하므로, 삭제한 뒤 새로 매칭을 찾는 격자점 한 칸에 대해서만 이분 매칭을 수행해주면 시간 초과를 피해 AC를 받을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1441&quot; data-origin-height=&quot;1461&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kO5I8/btrPDa7Z3Y6/AUiNWPMsEoy27glDkefLRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kO5I8/btrPDa7Z3Y6/AUiNWPMsEoy27glDkefLRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kO5I8/btrPDa7Z3Y6/AUiNWPMsEoy27glDkefLRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkO5I8%2FbtrPDa7Z3Y6%2FAUiNWPMsEoy27glDkefLRk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;513&quot; height=&quot;520&quot; data-origin-width=&quot;1441&quot; data-origin-height=&quot;1461&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666839656812&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj1, adj2;
vector&amp;lt;int&amp;gt; l1, r1, l2, r2;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj1[x].size(); i++) {
        int y = adj1[x][i];

        if(r1[y] == -1 || (!vis[r1[y]] &amp;amp;&amp;amp; f(r1[y]))) {
            l1[x] = y, r1[y] = x;

            return true;
        }
    }

    return false;
}

bool g(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj2[x].size(); i++) {
        int y = adj2[x][i];

        if(r2[y] == -1 || (!vis[r2[y]] &amp;amp;&amp;amp; g(r2[y]))) {
            l2[x] = y, r2[y] = x;

            return true;
        }
    }

    return false;
}

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; tadj;
vector&amp;lt;int&amp;gt; ll, rr;

bool h(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;tadj[x].size(); i++) {
        int y = tadj[x][i];

        if(rr[y] == -1 || (!vis[rr[y]] &amp;amp;&amp;amp; h(rr[y]))) {
            ll[x] = y, rr[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    while(true) {
        int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;
        if(N == 0 &amp;amp;&amp;amp; M == 0) break;

        vector&amp;lt;vector&amp;lt;char&amp;gt;&amp;gt; v(N+1, vector&amp;lt;char&amp;gt;(M+1));

        for(int i=1; i&amp;lt;=N; i++)
            for(int j=1; j&amp;lt;=M; j++) cin &amp;gt;&amp;gt; v[i][j];

        int s = (N*M + 1) / 2;

        int di[4] = {1, -1, 0, 0};
        int dj[4] = {0, 0, 1, -1};

        adj1.clear();
        adj1.resize(s+1);

        for(int i=1; i&amp;lt;=N; i++)
            for(int j=!(i%2)+1; j&amp;lt;=M; j+=2) {
                if(v[i][j] != '.') continue;

                for(int k=0; k&amp;lt;4; k++) {
                    int ni = i + di[k];
                    int nj = j + dj[k];

                    if(ni &amp;lt; 1 || nj &amp;lt; 1 || ni &amp;gt; N || nj &amp;gt; M) continue;
                    if(v[ni][nj] != '.') continue;

                    adj1[((i-1)*M+j+1)/2].push_back(((ni-1)*M+nj+1)/2);
                }
            }

        l1.clear();
        l1.resize(s+1, -1);

        r1.clear();
        r1.resize(s+1, -1);

        for(int i=1; i&amp;lt;=s; i++) {
            vis.clear();
            vis.resize(s+1);

            f(i);
        }

        adj2.clear();
        adj2.resize(s+1);

        for(int i=1; i&amp;lt;=N; i++)
            for(int j=(i%2)+1; j&amp;lt;=M; j+=2) {
                if(v[i][j] != '.') continue;

                for(int k=0; k&amp;lt;4; k++) {
                    int ni = i + di[k];
                    int nj = j + dj[k];

                    if(ni &amp;lt; 1 || nj &amp;lt; 1 || ni &amp;gt; N || nj &amp;gt; M) continue;
                    if(v[ni][nj] != '.') continue;

                    adj2[((i-1)*M+j+1)/2].push_back(((ni-1)*M+nj+1)/2);
                }
            }

        l2.clear();
        l2.resize(s+1, -1);

        r2.clear();
        r2.resize(s+1, -1);

        for(int i=1; i&amp;lt;=s; i++) {
            vis.clear();
            vis.resize(s+1);

            g(i);
        }

        vector&amp;lt;vector&amp;lt;char&amp;gt;&amp;gt; w(v);

        for(int ii=1; ii&amp;lt;=N; ii++)
            for(int jj=1; jj&amp;lt;=M; jj++) {
                if(v[ii][jj] != '.') continue;

                int x = ((ii-1)*M+jj+1)/2;

                bool check = false;

                if((ii + jj) % 2 == 1 &amp;amp;&amp;amp; r1[x] == -1) check = true;
                if((ii + jj) % 2 == 0 &amp;amp;&amp;amp; r2[x] == -1) check = true;

                if(check) {
                    w[ii][jj] = 'B';
                    continue;
                }

                if((ii + jj) % 2 == 1) {
                    tadj.clear(); tadj = adj1;

                    for(int k=0; k&amp;lt;4; k++) {
                        int ni = ii + di[k];
                        int nj = jj + dj[k];

                        if(ni &amp;lt; 1 || nj &amp;lt; 1 || ni &amp;gt; N || nj &amp;gt; M) continue;
                        if(v[ni][nj] != '.') continue;

                        int y = ((ni-1)*M+nj+1)/2;

                        if(count(tadj[y].begin(), tadj[y].end(), x) &amp;gt; 0)
                            tadj[y].erase(remove(tadj[y].begin(), tadj[y].end(), x), tadj[y].end());
                    }

                    ll.clear(); ll = l1;
                    rr.clear(); rr = r1;

                    int z = rr[x];

                    ll[rr[x]] = -1;
                    rr[x] = -1;

                    vis.clear(); vis.resize(s+1);

                    if(h(z)) w[ii][jj] = 'B';
                    else w[ii][jj] = 'A';
                }
                if((ii + jj) % 2 == 0) {
                    tadj.clear(); tadj = adj2;

                    for(int k=0; k&amp;lt;4; k++) {
                        int ni = ii + di[k];
                        int nj = jj + dj[k];

                        if(ni &amp;lt; 1 || nj &amp;lt; 1 || ni &amp;gt; N || nj &amp;gt; M) continue;
                        if(v[ni][nj] != '.') continue;

                        int y = ((ni-1)*M+nj+1)/2;

                        if(count(tadj[y].begin(), tadj[y].end(), x) &amp;gt; 0)
                            tadj[y].erase(remove(tadj[y].begin(), tadj[y].end(), x), tadj[y].end());
                    }

                    ll.clear(); ll = l2;
                    rr.clear(); rr = r2;

                    vis.clear(); vis.resize(s+1);

                    int z = rr[x];

                    ll[rr[x]] = -1;
                    rr[x] = -1;

                    if(h(z)) w[ii][jj] = 'B';
                    else w[ii][jj] = 'A';
                }
            }

        for(int i=1; i&amp;lt;=N; i++) {
            for(int j=1; j&amp;lt;=M; j++) cout &amp;lt;&amp;lt; w[i][j];
            cout &amp;lt;&amp;lt; &quot;\n&quot;;
        }
        cout &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 2051번 : 최소 버텍스 커버&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이분 그래프가 주어질 때 최소 정점 커버에 해당하는 정점들의 목록을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중요한 문제이므로 위에다가 배치한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1667008060437&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;백준 BOJ 10058번 : 센서 네트워크 풀이 (난이도 Ruby V / 루비 5)&quot; data-og-description=&quot;백준에서 3600문제 넘게 풀면서 루비 난이도 문제를 처음으로 푼 기념으로 이 문제만 별개의 포스트로 정리해본다. 무려 월드 파이널 문제이며 그 해 문제 중에서도 solved.ac 기준으로 난이도가 가&quot; data-og-host=&quot;restudycafe.tistory.com&quot; data-og-source-url=&quot;https://restudycafe.tistory.com/636&quot; data-og-url=&quot;https://restudycafe.tistory.com/636&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/XTWVy/hyQnXjMyjM/7NZLDQHBY2hlKVwLKn9dl1/img.png?width=800&amp;amp;height=512&amp;amp;face=0_0_800_512,https://scrap.kakaocdn.net/dn/cJOeke/hyQnQyca5S/1cDxdmYE6SILbyu70Dcxe1/img.png?width=800&amp;amp;height=512&amp;amp;face=0_0_800_512,https://scrap.kakaocdn.net/dn/t4Np5/hyQn3j0zwz/tLkAAATzf37klIbO3Vo5yK/img.png?width=1401&amp;amp;height=897&amp;amp;face=0_0_1401_897&quot;&gt;&lt;a href=&quot;https://restudycafe.tistory.com/636&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://restudycafe.tistory.com/636&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/XTWVy/hyQnXjMyjM/7NZLDQHBY2hlKVwLKn9dl1/img.png?width=800&amp;amp;height=512&amp;amp;face=0_0_800_512,https://scrap.kakaocdn.net/dn/cJOeke/hyQnQyca5S/1cDxdmYE6SILbyu70Dcxe1/img.png?width=800&amp;amp;height=512&amp;amp;face=0_0_800_512,https://scrap.kakaocdn.net/dn/t4Np5/hyQn3j0zwz/tLkAAATzf37klIbO3Vo5yK/img.png?width=1401&amp;amp;height=897&amp;amp;face=0_0_1401_897');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;백준 BOJ 10058번 : 센서 네트워크 풀이 (난이도 Ruby V / 루비 5)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;백준에서 3600문제 넘게 풀면서 루비 난이도 문제를 처음으로 푼 기념으로 이 문제만 별개의 포스트로 정리해본다. 무려 월드 파이널 문제이며 그 해 문제 중에서도 solved.ac 기준으로 난이도가 가&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;restudycafe.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 포스트의 중간에 정리된 정리를 사용하면 된다. (&lt;b&gt;최소 정점 커버 = (L - X) &amp;cup; (R &amp;cap; X)&lt;/b&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최소 정점 커버에 대한 엄밀한 증명은 kks227님의 블로그에 정리되어있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1667008040088&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    adj.resize(N+1);

    for(int i=1; i&amp;lt;=N; i++) {
        int K; cin &amp;gt;&amp;gt; K;

        while(K--) {
            int x; cin &amp;gt;&amp;gt; x;

            adj[i].push_back(x);
        }
    }

    l.resize(N+1, -1);
    r.resize(M+1, -1);

    int match = 0;

    for(int i=1; i&amp;lt;=N; i++) {
        vis.clear();
        vis.resize(N+1);

        f(i);
    }

    vector&amp;lt;bool&amp;gt; lvis(N+1), rvis(M+1);

    for(int i=1; i&amp;lt;=N; i++) {
        if(l[i] != -1 || lvis[i]) continue;

        lvis[i] = true;

        queue&amp;lt;pair&amp;lt;bool, int&amp;gt;&amp;gt; q;
        q.push({true, i});

        while(!q.empty()) {
            bool isLeft = q.front().first;
            int x = q.front().second;
            q.pop();

            if(isLeft) {
                for(int j=0; j&amp;lt;adj[x].size(); j++) {
                    int y = adj[x][j];

                    if(l[x] != y &amp;amp;&amp;amp; !rvis[y]) {
                        rvis[y] = true;
                        q.push({false, y});
                    }
                }
            }
            else {
                for(int j=1; j&amp;lt;=N; j++) {
                    int y = j;

                    if(lvis[y]) continue;
                    if(count(adj[y].begin(), adj[y].end(), x) == 0) continue;

                    for(int k=0; k&amp;lt;adj[y].size(); k++) {
                        if(adj[y][k] != x) continue;

                        if(r[x] == y) {
                            lvis[y] = true;
                            q.push({true, y});
                        }
                    }
                }
            }
        }
    }

    vector&amp;lt;int&amp;gt; v, u;

    for(int i=1; i&amp;lt;=N; i++)
        if(!lvis[i]) v.push_back(i);

    for(int i=1; i&amp;lt;=M; i++)
        if(rvis[i]) u.push_back(i);

    cout &amp;lt;&amp;lt; v.size() + u.size() &amp;lt;&amp;lt; &quot;\n&quot;;

    cout &amp;lt;&amp;lt; v.size() &amp;lt;&amp;lt; &quot; &quot;;

    for(int i=0; i&amp;lt;v.size(); i++) cout &amp;lt;&amp;lt; v[i] &amp;lt;&amp;lt; &quot; &quot;;
    cout &amp;lt;&amp;lt; &quot;\n&quot;;

    cout &amp;lt;&amp;lt; u.size() &amp;lt;&amp;lt; &quot; &quot;;

    for(int i=0; i&amp;lt;u.size(); i++) cout &amp;lt;&amp;lt; u[i] &amp;lt;&amp;lt; &quot; &quot;;
    cout &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 13980번 : Maximum Islands&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N x M 크기의 배열이 주어지고, L은 땅, W은 물, C는 구름으로 가려져서 어떤 것인지 보이지 않는다고 했을 때, 상하좌우가 물로 분리된 땅 덩어리를 섬이라고 한다면 가능한 섬의 최댓값을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최대 정점 커버를 활용하여 이분 매칭으로 풀이할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;L은 이미 땅이니 인접한 부분 중 C가 모두 물이라고 생각해도 가능한 최대 섬의 수에 영향을 주지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 인접한 부분에 L이 없는 C들을 가지고 이분 매칭을 수행하여 최대 매칭 수를 그러한 C들의 수에서 빼주면, 추가로 형성할 수 있는 최대 섬의 수가 된다. (최대 정점 커버 = 정점 수 - 최대 매칭 수라는 정리를 사용한 것이다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 기존의 L은 DFS 등으로 탐색하여 섬의 수를 세어주고, 나머지는 이분 매칭으로 풀이해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666495871298&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

int N, M;
vector&amp;lt;vector&amp;lt;char&amp;gt;&amp;gt; v;
vector&amp;lt;vector&amp;lt;bool&amp;gt;&amp;gt; lvis;

void g(int x, int y) {
    lvis[x][y] = true;

    int dx[4] = {1, -1, 0, 0};
    int dy[4] = {0, 0, 1, -1};

    for(int i=0; i&amp;lt;4; i++) {
        int nx = x + dx[i];
        int ny = y + dy[i];

        if(nx &amp;lt; 1 || ny &amp;lt; 1 || nx &amp;gt; N || ny &amp;gt; M) continue;
        if(v[nx][ny] != 'L' || lvis[nx][ny]) continue;

        g(nx, ny);
    }
}

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    v.resize(N+1, vector&amp;lt;char&amp;gt;(M+1));

    for(int i=1; i&amp;lt;=N; i++)
        for(int j=1; j&amp;lt;=M; j++) cin &amp;gt;&amp;gt; v[i][j];

    lvis.resize(N+1, vector&amp;lt;bool&amp;gt;(M+1));
    int lnd = 0;

    for(int i=1; i&amp;lt;=N; i++)
        for(int j=1; j&amp;lt;=M; j++)
            if(v[i][j] == 'L' &amp;amp;&amp;amp; !lvis[i][j]) {
                g(i, j);
                lnd++;
            }

    vector&amp;lt;vector&amp;lt;bool&amp;gt;&amp;gt; u(N+1, vector&amp;lt;bool&amp;gt;(M+1));
    int cnt = 0;

    for(int i=1; i&amp;lt;=N; i++)
        for(int j=1; j&amp;lt;=M; j++) {
            if(v[i][j] != 'C') continue;

            int di[4] = {1, -1, 0, 0};
            int dj[4] = {0, 0, 1, -1};

            bool check = true;

            for(int k=0; k&amp;lt;4; k++) {
                int ni = i + di[k];
                int nj = j + dj[k];

                if(ni &amp;lt; 1 || nj &amp;lt; 1 || ni &amp;gt; N || nj &amp;gt; M) continue;
                if(v[ni][nj] == 'L') check = false;
            }

            if(check) {
                u[i][j] = true;
                cnt++;
            }
        }

    int s = (N*M + 1) / 2;

    adj.resize(s+1);

    for(int i=1; i&amp;lt;=N; i++)
        for(int j=!(i%2)+1; j&amp;lt;=M; j+=2) {
            if(!u[i][j]) continue;

            int di[4] = {1, -1, 0, 0};
            int dj[4] = {0, 0, 1, -1};

            for(int k=0; k&amp;lt;4; k++) {
                int ni = i + di[k];
                int nj = j + dj[k];

                if(ni &amp;lt; 1 || nj &amp;lt; 1 || ni &amp;gt; N || nj &amp;gt; M) continue;
                if(v[ni][nj] != 'C' || !u[ni][nj]) continue;

                adj[((i-1)*M+j+1)/2].push_back(((ni-1)*M+nj+1)/2);
            }
        }

    l.resize(s+1, -1);
    r.resize(s+1, -1);

    int match = 0;

    for(int i=1; i&amp;lt;=s; i++) {
        vis.clear();
        vis.resize(s+1);

        if(f(i)) match++;
    }

    int ans = lnd + cnt - match;

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 12428번 : 박테리아 (Large)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;** 이 문제의 풀이 코드로 &lt;b&gt;백준 BOJ 12427번 : 박테리아 (Small)&lt;/b&gt; 문제를 정답 처리 받을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N x M x K 크기의 배열이 주어질 때, K개의 각 층에서 상하좌우로 인접한 .은 하나의 방이고, 상하 모두 방인 칸끼리는 박테리아를 보관할 수 없다고 할 때, 최대 몇 개의 방에 박테리아를 보관할 수 있는지 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 DFS 또는 BFS로 각 층에 있는 방들에 번호를 매기고, 각 층에 대해 각 방 칸의 위 아래 칸에 방이 인접해있는지를 검사하여 해당 방의 번호들끼리 간선을 연결한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 이분 그래프가 형성되어야 이분 매칭을 수행할 수 있으므로, 홀수번째 층과 짝수번째 층을 나누어 매칭해준다. (2층 이상 떨어진 칸은 절대로 인접할 수 없으므로 이분 그래프가 만들어진다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 이분 매칭을 수행해준 뒤 방의 수에서 매칭의 수를 빼주면 답이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666926549960&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    for(int t=1; t&amp;lt;=T; t++) {
        int N, M, K; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M &amp;gt;&amp;gt; K;

        vector&amp;lt;vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt;&amp;gt; v(K+1, vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt;(N+1, vector&amp;lt;int&amp;gt;(M+1, -1)));

        for(int i=1; i&amp;lt;=K; i++)
            for(int j=1; j&amp;lt;=N; j++)
                for(int k=1; k&amp;lt;=M; k++) {
                    char ch; cin &amp;gt;&amp;gt; ch;

                    if(ch == '.') v[i][j][k] = 0;
                }

        int cnt = 0;

        for(int i=1; i&amp;lt;=K; i++)
            for(int j=1; j&amp;lt;=N; j++)
                for(int k=1; k&amp;lt;=M; k++) {
                    if(v[i][j][k] != 0) continue;

                    cnt++;
                    v[i][j][k] = cnt;

                    queue&amp;lt;pair&amp;lt;int, int&amp;gt;&amp;gt; q;
                    q.push({j, k});

                    vector&amp;lt;vector&amp;lt;bool&amp;gt;&amp;gt; vis(N+1, vector&amp;lt;bool&amp;gt;(M+1));
                    vis[j][k] = true;

                    while(!q.empty()) {
                        int x = q.front().first;
                        int y = q.front().second;
                        q.pop();

                        int dx[4] = {1, -1, 0, 0};
                        int dy[4] = {0, 0, 1, -1};

                        for(int l=0; l&amp;lt;4; l++) {
                            int nx = x + dx[l];
                            int ny = y + dy[l];

                            if(nx &amp;lt; 1 || ny &amp;lt; 1 || nx &amp;gt; N || ny &amp;gt; M) continue;
                            if(v[i][nx][ny] != 0) continue;

                            v[i][nx][ny] = cnt;
                            q.push({nx, ny});
                        }
                    }
                }

        adj.clear();
        adj.resize(cnt+1);

        for(int i=1; i&amp;lt;=K; i+=2)
            for(int j=1; j&amp;lt;=N; j++)
                for(int k=1; k&amp;lt;=M; k++) {
                    if(v[i][j][k] == -1) continue;

                    int dz[2] = {1, -1};

                    for(int l=0; l&amp;lt;2; l++) {
                        int nz = i + dz[l];

                        if(nz &amp;lt; 1 || nz &amp;gt; K) continue;
                        if(v[nz][j][k] == -1) continue;

                        adj[v[i][j][k]].push_back(v[nz][j][k]);
                    }
                }

        l.clear(); l.resize(cnt+1, -1);
        r.clear(); r.resize(cnt+1, -1);

        int match = 0;

        for(int i=1; i&amp;lt;=cnt; i++) {
            vis.clear();
            vis.resize(cnt+1);

            if(f(i)) match++;
        }

        int ans = cnt - match;

        cout &amp;lt;&amp;lt; &quot;Case #&quot; &amp;lt;&amp;lt; t &amp;lt;&amp;lt; &quot;: &quot; &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 12634번 : Stock Charts (Large)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;** 이 문제의 풀이 코드로 &lt;b&gt;백준 BOJ 12988번 : 주식 차트&lt;/b&gt;, &lt;b&gt;백준 BOJ 12633번 : Stock Charts (Small)&lt;/b&gt; 문제를 정답 처리 받을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(12988번은 테스트케이스 부분을 조금만 수정해주면 된다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 주식 차트가 주어지는데, 서로 차트가 겹치는 것은 같은 차트에 넣을 수 없다고 한다면 차트가 최소 몇 개 필요한지 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역시 최대 매칭을 구한 뒤 매칭 수만큼 빼주면 되는 것으로 보이는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당연히 일반 그래프에서의 최대 매칭은 구현하기 매우 어려우므로, 주어진 상황을 &lt;b&gt;이분 그래프&lt;/b&gt;로 만드는 것이 핵심이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해결책은 그래프의 상하 관계대로만 간선을 연결하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 &lt;span style=&quot;color: #ee2323;&quot;&gt;2번 그래프가 3번 그래프보다 위에 있다면, 2번 노드에서 3번 노드로 간선을 연결&lt;/span&gt;하는 것이다. (&lt;u&gt;3번 노드에서 2번 노드로 연결하는 것이 아니라&lt;/u&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 방식으로 간선들을 연결해준다면, 최대 매칭을 구했을 때 얻어지는 매칭 수만큼 차트의 개수를 줄일 수 있고 반례가 존재하지 않게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666926698057&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    for(int t=1; t&amp;lt;=T; t++) {
        int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

        vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; v(N, vector&amp;lt;int&amp;gt;(M));

        for(int i=0; i&amp;lt;N; i++)
            for(int j=0; j&amp;lt;M; j++) cin &amp;gt;&amp;gt; v[i][j];

        adj.clear();
        adj.resize(N);

        for(int i=0; i&amp;lt;N; i++)
            for(int j=0; j&amp;lt;N; j++) {
                if(i == j) continue;

                bool check = true;

                for(int k=0; k&amp;lt;M; k++)
                    if(v[i][k] &amp;gt;= v[j][k]) check = false;

                if(check) adj[i].push_back(j);
            }

        l.clear(); l.resize(N, -1);
        r.clear(); r.resize(N, -1);

        int match = 0;

        for(int i=0; i&amp;lt;N; i++) {
            vis.clear();
            vis.resize(N);

            if(f(i)) match++;
        }

        int ans = N - match;

        cout &amp;lt;&amp;lt; &quot;Case #&quot; &amp;lt;&amp;lt; t &amp;lt;&amp;lt; &quot;: &quot; &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 15007번 : Easter Eggs&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2차원 좌표 평면 상에 N개의 파란 점과 M개의 빨간 점이 주어지고, 이들 중 K개의 점을 선택하여 빨간 점과 파란 점의 최소 거리가 최대가 되도록 했을 때 그 거리를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거리 임계 값에 대해 이분 탐색을 수행하면서, 현재 임계 거리 값 이하가 되는 것들에 대해 간선을 연결하여 (파란 점 &amp;rarr; 빨간 점 방향으로 연결한다.) 이분 매칭을 수행해준 뒤 최대 정점 독립 집합이 K 이상이면 답의 최댓값을 갱신해주는 방식으로 답을 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666989588426&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(x == y) continue;

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    for(int t=1; t&amp;lt;=T; t++) {
        int N; cin &amp;gt;&amp;gt; N;

        adj.clear();
        adj.resize(N+1);

        map&amp;lt;string, int&amp;gt; m1, m2;

        int x = 0, y = 0;

        for(int i=1; i&amp;lt;=N; i++) {
            string a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

            if(m1[a] == 0) m1[a] = ++x;
            if(m2[b] == 0) m2[b] = ++y;
            
            
        }

        l.clear(); l.resize(N+1, -1);
        r.clear(); r.resize(N+1, -1);

        int ans = 0;

        for(int i=1; i&amp;lt;=N; i++) {
            vis.clear();
            vis.resize(N+1);

            if(f(i)) ans++;
        }

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 17994번 : Swap Free&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 애너그램 관계인 단어들이 주어질 때, 이들 중 몇 개를 선택하여 만든 집합들 중 어떤 두 단어를 골라도 두 철자를 한 번만 swap하여 만들 수 있는 단어 관계가 없도록 하는 최대 집합 크기를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단어 A에서 B를 만들 때 최소 x번 swap하여야 하고, B에서 C를 만들 때 최소 y번 swap해야 하고, A에서 C를 만들 때 z번 swap해야 한다면 x + y와 z의 홀짝성이 동일하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 첫 번째 단어에서 홀수 횟수만큼 swap해야 만들 수 있는 단어들은 오른쪽에, 짝수 횟수만큼 swap해야 만들 수 있는 단어들은 왼쪽에 (첫 번째 단어 포함, 0번이니까) 위치시킨 뒤 이분 매칭을 통해 최대 정점 독립 집합의 크기를 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666989795701&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(x == y) continue;

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    for(int t=1; t&amp;lt;=T; t++) {
        int N; cin &amp;gt;&amp;gt; N;

        adj.clear();
        adj.resize(N+1);

        map&amp;lt;string, int&amp;gt; m1, m2;

        int x = 0, y = 0;

        for(int i=1; i&amp;lt;=N; i++) {
            string a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

            if(m1[a] == 0) m1[a] = ++x;
            if(m2[b] == 0) m2[b] = ++y;
            
            
        }

        l.clear(); l.resize(N+1, -1);
        r.clear(); r.resize(N+1, -1);

        int ans = 0;

        for(int i=1; i&amp;lt;=N; i++) {
            vis.clear();
            vis.resize(N+1);

            if(f(i)) ans++;
        }

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 7064번 : Air Raid&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;루프 없는 단방향 그래프가 주어질 때, 서로 경로가 겹치지 않고 모든 노드를 방문할 수 있는 최소 사람 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;양쪽에 각각 N개의 노드를 두고 간선 방향대로 간선을 연결한 뒤, 최대 매칭을 찾아주면 매칭 수만큼 필요한 사람 수가 줄어들게 되므로 N - (최대 매칭 수)가 답이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666990266220&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    while(T--) {
        int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

        adj.clear();
        adj.resize(N+1);

        while(M--) {
            int x, y; cin &amp;gt;&amp;gt; x &amp;gt;&amp;gt; y;

            adj[x].push_back(y);
        }

        l.clear(); l.resize(N+1, -1);
        r.clear(); r.resize(N+1, -1);

        int match = 0;

        for(int i=1; i&amp;lt;=N; i++) {
            vis.clear();
            vis.resize(N+1);

            if(f(i)) match++;
        }

        int ans = N - match;

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 19647번 : Unique Solution&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이분 그래프에서 N개 모두 매칭이 가능한 경우가 유일한지를 검사하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이분 매칭 함수를 두 개 구현하여 하나는 앞에서부터 탐색하고 하나는 뒤에서부터 탐색하여 두 해가 동일한지 확인해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666990351086&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l1, r1, l2, r2;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(r1[y] == -1 || (!vis[r1[y]] &amp;amp;&amp;amp; f(r1[y]))) {
            l1[x] = y, r1[y] = x;

            return true;
        }
    }

    return false;
}

bool g(int x) {
    vis[x] = true;

    for(int i=adj[x].size()-1; i&amp;gt;=0; i--) {
        int y = adj[x][i];

        if(r2[y] == -1 || (!vis[r2[y]] &amp;amp;&amp;amp; g(r2[y]))) {
            l2[x] = y, r2[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    adj.resize(N+1);

    for(int i=1; i&amp;lt;=N; i++) {
        int M; cin &amp;gt;&amp;gt; M;

        while(M--) {
            int x; cin &amp;gt;&amp;gt; x;

            adj[i].push_back(x);
        }
    }

    l1.resize(N+1, -1);
    r1.resize(N+1, -1);

    for(int i=1; i&amp;lt;=N; i++) {
        vis.clear();
        vis.resize(N+1);

        f(i);
    }

    l2.resize(N+1, -1);
    r2.resize(N+1, -1);

    for(int i=1; i&amp;lt;=N; i++) {
        vis.clear();
        vis.resize(N+1);

        g(i);
    }

    if(l1 != l2) {
        cout &amp;lt;&amp;lt; -1 &amp;lt;&amp;lt; &quot;\n&quot;;
        return 0;
    }

    cout &amp;lt;&amp;lt; 1 &amp;lt;&amp;lt; &quot;\n&quot;;

    for(int i=1; i&amp;lt;=N; i++) cout &amp;lt;&amp;lt; l1[i] &amp;lt;&amp;lt; &quot; &quot;;
    cout &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/알고리즘 공부 내용 정리</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/635</guid>
      <comments>https://restudycafe.tistory.com/635#entry635comment</comments>
      <pubDate>Sun, 23 Oct 2022 12:31:15 +0900</pubDate>
    </item>
    <item>
      <title>이분 매칭 최대 독립 집합 (Maximum Independent Set) 외 문제 풀이</title>
      <link>https://restudycafe.tistory.com/634</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이 포스트에서는 이분 매칭의 응용 중 하나인 &lt;b&gt;최대 독립 집합&lt;/b&gt;(Maximum Independent Set)에 대해서 다룬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 노드들의 집합에서 어떤 두 노드도 서로 간선으로 연결되어 있지 않을 때, 이 집합을 독립 집합이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래프에서 최대 크기의 독립 집합을 최대 독립 집합이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이분 매칭 문제에서 &lt;u&gt;최대 독립 집합은 전체 노드에서 최소 정점 커버(= 최소 꼭짓점 덮개)를 뺀 나머지&lt;/u&gt;가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 최소 정점 커버는 쾨니그의 정리에 의해서 최대 매칭 수와 동일하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;span style=&quot;color: #ee2323;&quot;&gt;최대 독립 집합의 크기 I = V - M이다. (V = vertex의 수, M = 최대 매칭 수)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 14986번 : Punching Power&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum III&lt;/b&gt; &lt;/span&gt;(난이도 기여로 난이도 상향시킴)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기계를 설치할 수 있는 좌표들의 후보가 N개 주어지고, 거리가 1.3 이하인 두 지점에 모두 기계를 설치하는 것은 불가능하다고 할 때, 최대로 설치할 수 있는 기계의 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거리가 1.3 이하라면 결국은 인접한 칸 사이에만 설치되지 않도록 기계들을 배치하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인접한 노드들을 간선으로 연결한 뒤 여기에서 최대 독립 집합을 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 이를 위해서는 위에서 사용한 I = V - M의 식을 사용하기 위해 최대 매칭을 구해야 하므로 이분 그래프로 바꾸어줄 필요가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 (x + y) % 2 = 0인 칸과 (x + y) % 2 = 1인 칸 두 가지로 나눈다. (체스판의 검은 칸, 흰 칸과 같다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간선들로 연결해서 최대 매칭을 구해주고, N에서 이를 빼주면 답이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666356331070&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N;

    while(cin &amp;gt;&amp;gt; N) {
        vector&amp;lt;pair&amp;lt;int, int&amp;gt;&amp;gt; v, u;
        map&amp;lt;pair&amp;lt;int, int&amp;gt;, int&amp;gt; vm, um;
        int vcnt = 0, ucnt = 0;

        for(int i=0; i&amp;lt;N; i++) {
            int x, y; cin &amp;gt;&amp;gt; x &amp;gt;&amp;gt; y;

            if((x + y) % 2 == 0) {
                v.push_back({x, y});
                vm[{x, y}] = ++vcnt;
            }
            else {
                u.push_back({x, y});
                um[{x, y}] = ++ucnt;
            }
        }

        adj.clear();
        adj.resize(vcnt+1);

        for(int i=0; i&amp;lt;v.size(); i++) {
            int x = v[i].first;
            int y = v[i].second;

            int dx[4] = {1, -1, 0, 0};
            int dy[4] = {0, 0, 1, -1};

            for(int j=0; j&amp;lt;4; j++) {
                int nx = x + dx[j];
                int ny = y + dy[j];

                if(um[{nx, ny}] != 0) adj[vm[{x, y}]].push_back(um[{nx, ny}]);
            }
        }

        l.clear();
        l.resize(vcnt+1, -1);

        r.clear();
        r.resize(ucnt+1, -1);

        int match = 0;

        for(int i=1; i&amp;lt;=vcnt; i++) {
            vis.clear();
            vis.resize(vcnt+1);

            if(f(i)) match++;
        }

        int ans = N - match;

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 16726번 : 영과일 학회방&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N x M 크기의 배열이 주어질 때, 1 x 1 또는 1 x 2 블럭으로 맵의 빈칸을 채운다고 한다면 최소로 필요한 블럭의 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이분 매칭 개수의 여집합을 이용하는 대표적인 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;맵을 체스판처럼 생각하여, 검은색 칸에 해당하는 노드와 흰색 칸에 해당하는 노드들로 나누어 서로 붙어있는 빈칸 사이인 노드들을 간선으로 연결해준 뒤 이분 매칭을 수행&lt;/span&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최대 매칭 값은 최대로 놓을 수 있는 1 x 2 블럭의 수와 동일하므로, 전체 빈칸 수 - 1 x 2 블럭 수 = 총 블럭 수임을 이용하여 답을 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666352211595&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    vector&amp;lt;vector&amp;lt;char&amp;gt;&amp;gt; v(N+1, vector&amp;lt;char&amp;gt;(M+1));
    int cnt = 0;

    for(int i=1; i&amp;lt;=N; i++)
        for(int j=1; j&amp;lt;=M; j++) {
            cin &amp;gt;&amp;gt; v[i][j];

            if(v[i][j] == '.') cnt++;
        }

    adj.resize(N*M + 1);

    for(int i=1; i&amp;lt;=N; i++)
        for(int j=!(i%2)+1; j&amp;lt;=M; j+=2) {
            if(v[i][j] != '.') continue;

            int di[4] = {1, -1, 0, 0};
            int dj[4] = {0, 0, 1, -1};

            for(int k=0; k&amp;lt;4; k++) {
                int ni = i + di[k];
                int nj = j + dj[k];

                if(ni &amp;lt; 1 || nj &amp;lt; 1 || ni &amp;gt; N || nj &amp;gt; M) continue;
                if(v[ni][nj] != '.') continue;

                adj[((i-1)*M+j+1)/2].push_back(((ni-1)*M+nj+1)/2);
            }
        }

    int s = (N*M + 1) / 2;

    l.resize(s+1, -1);
    r.resize(s+1, -1);

    int match = 0;

    for(int i=1; i&amp;lt;=s; i++) {
        vis.clear();
        vis.resize(s+1);

        if(f(i)) match++;
    }

    int ans = cnt - match;

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 7058번 : Royal guards&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N x M 배열이 주어지고, 0으로 된 칸은 경비병을 배치할 수 있는 칸, 1은 빈 칸이나 경비병을 배치할 수 없는 칸, 2는 벽이라고 할 때, 벽으로 막혀있지 않고 같은 행이나 열인 병사끼리는 서로 공격한다고 할 때, 서로 공격하지 않도록 경비병을 배치하는 최대 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 0으로 된 빈칸에 행과 열 번호를 부여하고, 행 번호와 열 번호 사이의 이분 그래프를 만들어준 뒤 최대 매칭을 찾아주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제를 상단에 배치한 이유는 바로 매칭을 구해야하기 때문인데, 이것은 각 {i, l[i]} 값들에 해당하는 행 번호와 열 번호를 가지고 있는 칸을 반복문으로 찾아주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666375816552&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; v(N+1, vector&amp;lt;int&amp;gt;(M+1));

    for(int i=1; i&amp;lt;=N; i++)
        for(int j=1; j&amp;lt;=M; j++) cin &amp;gt;&amp;gt; v[i][j];

    vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; u(N+1, vector&amp;lt;int&amp;gt;(M+1));
    int rcnt = 1;

    for(int i=1; i&amp;lt;=N; i++)
        for(int j=1; j&amp;lt;=M; j++) {
            if(v[i][j] == 0) u[i][j] = rcnt;
            if(v[i][j] != 2 &amp;amp;&amp;amp; (j == M || v[i][j+1] == 2)) rcnt++;
        }

    rcnt--;

    vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; w(N+1, vector&amp;lt;int&amp;gt;(M+1));
    int ccnt = 1;

    for(int i=1; i&amp;lt;=M; i++)
        for(int j=1; j&amp;lt;=N; j++) {
            if(v[j][i] == 0) w[j][i] = ccnt;
            if(v[j][i] != 2 &amp;amp;&amp;amp; (j == N || v[j+1][i] == 2)) ccnt++;
        }

    ccnt--;

    adj.resize(rcnt+1);

    for(int i=1; i&amp;lt;=N; i++)
        for(int j=1; j&amp;lt;=M; j++)
            if(v[i][j] == 0) adj[u[i][j]].push_back(w[i][j]);


    l.resize(rcnt+1, -1);
    r.resize(ccnt+1, -1);

    int ans = 0;

    for(int i=1; i&amp;lt;=rcnt; i++) {
        vis.clear();
        vis.resize(rcnt+1);

        if(f(i)) ans++;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;

    vector&amp;lt;pair&amp;lt;int, int&amp;gt;&amp;gt; vv;

    for(int i=1; i&amp;lt;=rcnt; i++)
                if(i == r[l[i]]) vv.push_back({i, l[i]});

    for(int i=0; i&amp;lt;vv.size(); i++)
        for(int j=1; j&amp;lt;=N; j++)
            for(int k=1; k&amp;lt;=M; k++)
                if(u[j][k] == vv[i].first &amp;amp;&amp;amp; w[j][k] == vv[i].second) cout &amp;lt;&amp;lt; j &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; k &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 2787번 : 흔한 수열 문제&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N 이하의 자연수로 이루어진 길이 N인 순열이 있고, M개의 힌트가 주어질 때 순열을 맞추는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 힌트란 2가지로 분류되는데, 1 a b c의 경우 a번째부터 b번째 수 중 최댓값이 c라는 것이고, 2 a b c의 경우 최솟값이 c라는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음의 두 가지 조건을 사용하면 된다. 1번 쿼리를 예시로 들겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 각 인덱스에 해당하는 최솟값을 1, 최댓값을 N으로 두고 구간을 좁힐 수 있다. 1 a b c이면 a번 원소부터 b번 원소들 중 최댓값을 기존의 최댓값과 c 중 더 작은 값으로 갱신할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 각 숫자가 나타나는 인덱스 범위의 최솟값을 1, 최댓값을 N으로 두고 구간을 좁힐 수 있다. a b c 쿼리에 대해, c라는 숫자는 기존의 최솟값과 a 중 더 큰 인덱스로 갱신이 가능하며, 반대로 인덱스의 최댓값과 b 중 더 작은 인덱스로 갱신이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 1, 2를 모두 만족하는 조합들만 뽑아 인덱스 &amp;rarr; 가능한 숫자로 연결시켜준 뒤 이분 매칭을 수행해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666349032999&quot; class=&quot;arduino&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    vector&amp;lt;int&amp;gt; minv(N+1, 1), maxv(N+1, N);
    vector&amp;lt;int&amp;gt; minr(N+1, 1), maxr(N+1, N);

    while(M--) {
        int Q, a, b, c; cin &amp;gt;&amp;gt; Q &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b &amp;gt;&amp;gt; c;

        if(Q == 1) {
            for(int i=a; i&amp;lt;=b; i++) maxv[i] = min(maxv[i], c);
        }
        else if(Q == 2) {
            for(int i=a; i&amp;lt;=b; i++) minv[i] = max(minv[i], c);
        }

        minr[c] = max(minr[c], a);
        maxr[c] = min(maxr[c], b);
    }

    adj.resize(N+1);

    for(int i=1; i&amp;lt;=N; i++)
        for(int j=minv[i]; j&amp;lt;=maxv[i]; j++)
            if(minr[j] &amp;lt;= i &amp;amp;&amp;amp; i &amp;lt;= maxr[j]) adj[i].push_back(j);

    l.resize(N+1, -1);
    r.resize(N+1, -1);

    int match = 0;

    for(int i=1; i&amp;lt;=N; i++) {
        vis.clear();
        vis.resize(N+1);

        if(f(i)) match++;
    }

    if(match &amp;lt; N) {
        cout &amp;lt;&amp;lt; -1 &amp;lt;&amp;lt; &quot;\n&quot;;
        return 0;
    }

    for(int i=1; i&amp;lt;=N; i++) cout &amp;lt;&amp;lt; l[i] &amp;lt;&amp;lt; &quot; &quot;;
    cout &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 22620번 : Defend the Bases&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭, 이분 탐색&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 군대의 좌표와 이동 속도, M개의 기지의 좌표가 주어질 때 모든 기지에 하나 이상의 군대를 배치하기 위해 필요한 최소 시간을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 제한 시간이 주어지고 최대로 하나 이상의 군대를 배치할 수 있는 기지의 수를 구하는 문제라면 이분 매칭으로 쉽게 구할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 이 상황을 확장시켜 이분 탐색으로 미리 제한 시간을 가정하고, 그에 따른 match 값이 M인 경우 제한 시간을 줄여나가는 식으로 풀이할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666264120319&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { double x, y, v; };

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    cout &amp;lt;&amp;lt; fixed;
    cout.precision(8);

    while(true) {
        int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;
        if(N == 0 &amp;amp;&amp;amp; M == 0) break;

        vector&amp;lt;s&amp;gt; v(N), u(M);

        for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i].x &amp;gt;&amp;gt; v[i].y &amp;gt;&amp;gt; v[i].v;
        for(int i=0; i&amp;lt;M; i++) cin &amp;gt;&amp;gt; u[i].x &amp;gt;&amp;gt; u[i].y;

        double ll = 0, rr = INT_MAX, ans = INT_MAX, tr = 1e2;

        while(tr--) {
            double m = (ll + rr) / 2;

            adj.clear();
            adj.resize(M);

            for(int i=0; i&amp;lt;N; i++)
                for(int j=0; j&amp;lt;M; j++)
                    if(sqrt(pow(v[i].x - u[j].x, 2) + pow(v[i].y - u[j].y, 2)) / v[i].v &amp;lt;= m) adj[j].push_back(i);

            l.clear();
            l.resize(M, -1);

            r.clear();
            r.resize(N, -1);

            int match = 0;

            for(int i=0; i&amp;lt;M; i++) {
                vis.clear();
                vis.resize(M);

                if(f(i)) match++;
            }

            if(match == M) {
                ans = min(ans, m);
                rr = m;
            }
            else ll = m;
        }

        cout &amp;lt;&amp;lt; ll &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 13470번 : Programming Tutors&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭, 이분 탐색&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N명의 학생의 좌표와 N명의 교사의 좌표가 2차원 상에서 주어질 때, 하나의 교사가 서로 다른 하나의 학생으로 이동할 때 가장 맨해튼 거리가 먼 거리가 최소가 되도록 매치했을 때 그 최솟값을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 문제와 비슷한 방법으로, 이분 매칭을 하되 제한 값을 미리 정해두고 그 거리 이하인 노드들 내에서만 간선을 연결한 뒤 수행해준 뒤 매치된 쌍의 수가 N개이면 제한 거리를 줄여보고, 그렇지 않으면 제한 거리를 늘리는 식으로 조절해가면서 최소 제한 거리를 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666265607890&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { int x, y; };

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;s&amp;gt; v(N), u(N);

    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i].x &amp;gt;&amp;gt; v[i].y;
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; u[i].x &amp;gt;&amp;gt; u[i].y;

    int ll = 0, rr = INT_MAX, ans = INT_MAX;

    while(ll &amp;lt;= rr) {
        int m = (ll + rr) / 2;

        adj.clear();
        adj.resize(N);

        for(int i=0; i&amp;lt;N; i++)
            for(int j=0; j&amp;lt;N; j++)
                if(abs(v[i].x - u[j].x) + abs(v[i].y - u[j].y) &amp;lt;= m) adj[i].push_back(j);

        l.clear();
        l.resize(N, -1);

        r.clear();
        r.resize(N, -1);

        int match = 0;

        for(int i=0; i&amp;lt;N; i++) {
            vis.clear();
            vis.resize(N);

            if(f(i)) match++;
        }

        if(match == N) {
            ans = min(ans, m);
            rr = m - 1;
        }
        else ll = m + 1;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 9577번 : 토렌트&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 토렌트 조각이 있고 M명의 회원들이 접속한 시각에 해당 회원이 가지고 있는 조각 하나를 1초에 받을 수 있다고 할 때, 모든 조각을 모으기 위한 최소 시간을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이분 매칭으로 푸는 것을 알았다면, 어떤 그룹과 어떤 그룹 사이의 매칭을 수행할지 고민해보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 시간 (초 단위) &amp;rarr; 토렌트 조각 관계로 연결을 해준 뒤 이분 매칭 알고리즘을 돌려주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666323134468&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    while(T--) {
        int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

        adj.clear();
        adj.resize(101);

        while(M--) {
            int a, b, K; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b &amp;gt;&amp;gt; K;

            while(K--) {
                int x; cin &amp;gt;&amp;gt; x;

                for(int i=a; i&amp;lt;b; i++) adj[i].push_back(x);
            }
        }

        l.clear();
        l.resize(101, -1);

        r.clear();
        r.resize(N+1, -1);

        int match = 0;
        bool check = false;

        for(int i=0; i&amp;lt;=100; i++) {
            vis.clear();
            vis.resize(101);

            if(f(i)) match++;

            if(match == N) {
                cout &amp;lt;&amp;lt; i+1 &amp;lt;&amp;lt; &quot;\n&quot;;

                check = true;
                break;
            }
        }

        if(!check) cout &amp;lt;&amp;lt; -1 &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 25846번 : Make the Team&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 비디오가 있고 각각 시청 가능한 시간이 주어질 때, 모든 비디오를 시청 완료하는 가장 짧은 시간을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 비디오가 동일한 시간에 재생된다면 하나만 볼 수 있기 때문에, 각 시간에 볼 수 있는 비디오를 매칭하는 이분 매칭을 생각해볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;풀이 코드는 위의 문제와 거의 비슷하며, 변수의 범위만 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666324020166&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    adj.resize(1001);

    for(int i=0; i&amp;lt;N; i++) {
        int M; cin &amp;gt;&amp;gt; M;

        while(M--) {
            int x; cin &amp;gt;&amp;gt; x;

            adj[x].push_back(i);
        }
    }

    l.clear();
    l.resize(1001, -1);

    r.clear();
    r.resize(N, -1);

    int match = 0;

    for(int i=1; i&amp;lt;=1000; i++) {
        vis.clear();
        vis.resize(1001);

        if(f(i)) match++;

        if(match == N) {
            cout &amp;lt;&amp;lt; i+1 &amp;lt;&amp;lt; &quot;\n&quot;;
            break;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 3736번 : System Engineer&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 작업이 있고, 각 작업을 수행 가능한 서버들의 목록이 주어지며 하나의 서버에서는 하나의 작업만 수행이 가능하다면 동시에 수행할 수 있는 최대 작업의 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자열 처리만 조금 해주면 일반적인 이분 매칭으로 간단하게 풀이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666362261188&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N;

    while(cin &amp;gt;&amp;gt; N) {
        adj.clear();
        adj.resize(N);

        for(int i=0; i&amp;lt;N; i++) {
            int a, M; char ch;
            cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; ch &amp;gt;&amp;gt; ch &amp;gt;&amp;gt; M &amp;gt;&amp;gt; ch;

            while(M--) {
                int b; cin &amp;gt;&amp;gt; b;

                adj[a].push_back(b - N);
            }
        }

        l.clear();
        l.resize(N, -1);

        r.clear();
        r.resize(N, -1);

        int ans = 0;

        for(int i=0; i&amp;lt;N; i++) {
            vis.clear();
            vis.resize(N);

            if(f(i)) ans++;
        }

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 5780번 : Uncle Tom's Inherited Land&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N x M 크기의 배열이 있고 그들 중 연못에 해당하는 칸들의 목록이 주어질 때, 연못이 아닌 땅은 1 x 2 크기로 하나씩 판매할 수 있다고 할 때, 판매 가능한 땅의 최대 개수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 풀이한 &lt;b&gt;백준 BOJ 16726번 : 영과일 학회방&lt;/b&gt; 문제의 풀이와 비슷하게 풀이하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;체스판의 검은칸, 흰칸을 나누어 이분 매칭시켜준 뒤 두 칸이 모두 육지인 칸 사이를 간선으로 연결하고, 이분 매칭을 시켜 최대 매칭 수를 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666373001406&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    while(true) {
        int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;
        if(N == 0 &amp;amp;&amp;amp; M == 0) break;

        vector&amp;lt;vector&amp;lt;bool&amp;gt;&amp;gt; v(N+1, vector&amp;lt;bool&amp;gt;(M+1, true));

        int K; cin &amp;gt;&amp;gt; K;

        while(K--) {
            int x, y; cin &amp;gt;&amp;gt; x &amp;gt;&amp;gt; y;

            v[x][y] = false;
        }

        adj.clear();
        adj.resize(N*M + 1);

        for(int i=1; i&amp;lt;=N; i++)
            for(int j=!(i%2)+1; j&amp;lt;=M; j+=2) {
                if(!v[i][j]) continue;

                int di[4] = {1, -1, 0, 0};
                int dj[4] = {0, 0, 1, -1};

                for(int k=0; k&amp;lt;4; k++) {
                    int ni = i + di[k];
                    int nj = j + dj[k];

                    if(ni &amp;lt; 1 || nj &amp;lt; 1 || ni &amp;gt; N || nj &amp;gt; M) continue;
                    if(!v[ni][nj]) continue;

                    adj[((i-1)*M+j+1)/2].push_back(((ni-1)*M+nj+1)/2);
                }
            }

        int s = (N*M + 1) / 2;

        l.clear();
        l.resize(s+1, -1);

        r.clear();
        r.resize(s+1, -1);

        int ans = 0;

        for(int i=1; i&amp;lt;=s; i++) {
            vis.clear();
            vis.resize(s+1);

            if(f(i)) ans++;
        }

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 5924번 : Cow Steeplechase&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 선분이 가로선 또는 세로선으로 주어질 때, 이들 중 서로 겹치지 않는 것들을 최대한 뽑았을 때 그 개수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단, 평행한 두 선분이 겹치는 경우는 존재하지 않는다고 가정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가로 선분과 세로 선분을 서로 각각의 그룹으로 분류한 뒤 서로 교차하는 것끼리 간선으로 연결해주면 이분 그래프가 만들어지며, 여기에 이분 매칭을 사용하여 최대 매칭 수를 N에서 빼주면 답이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래의 가정 때문에 문제를 훨씬 간단하게 풀이할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 평행한 선분이 겹치지 않는다는 조건이 없었다면, 선분 교차 판정 알고리즘까지 가지고 와서 사용해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(그랬다면 난이도가 Platinum I 이상으로 올라갔을 것 같다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666374192184&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { int x1, y1, x2, y2; };

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;s&amp;gt; v, u;

    for(int i=0; i&amp;lt;N; i++) {
        int x1, y1, x2, y2; cin &amp;gt;&amp;gt; x1 &amp;gt;&amp;gt; y1 &amp;gt;&amp;gt; x2 &amp;gt;&amp;gt; y2;

        if(y1 == y2) {
            if(x1 &amp;gt; x2) swap(x1, x2);
            v.push_back({x1, y1, x2, y2});
        }
        else {
            if(y1 &amp;gt; y2) swap(y1, y2);
            u.push_back({x1, y1, x2, y2});
        }
    }

    adj.resize(v.size());

    for(int i=0; i&amp;lt;v.size(); i++)
        for(int j=0; j&amp;lt;u.size(); j++)
            if(v[i].x1 &amp;lt;= u[j].x1 &amp;amp;&amp;amp; u[j].x1 &amp;lt;= v[i].x2
               &amp;amp;&amp;amp; u[j].y1 &amp;lt;= v[i].y1 &amp;amp;&amp;amp; v[i].y1 &amp;lt;= u[j].y2) adj[i].push_back(j);

    l.resize(v.size(), -1);
    r.resize(u.size(), -1);

    int match = 0;

    for(int i=0; i&amp;lt;v.size(); i++) {
        vis.clear();
        vis.resize(v.size());

        if(f(i)) match++;
    }

    int ans = N - match;

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 10371번 : Irrigation Lines&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N x M 배열에 0 또는 1의 값이 주어질 때, 행 또는 열 몇 개를 선택하여 1이 전부 선택되도록 하는 최소 선택 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1의 값을 가지는 위치의 행과 열을 간선으로 이어 이분 그래프를 만들면, 쾨니그의 정리에 의해 최소 꼭짓점 덮개 수 = 최대 매칭 수이므로 이분 매칭으로 풀이할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666382482455&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    for(int t=1; t&amp;lt;=T; t++) {
        int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

        adj.clear();
        adj.resize(N+1);

        for(int i=1; i&amp;lt;=N; i++)
            for(int j=1; j&amp;lt;=M; j++) {
                char c; cin &amp;gt;&amp;gt; c;

                if(c == '1') adj[i].push_back(j);
            }

        l.clear();
        l.resize(N+1, -1);

        r.clear();
        r.resize(M+1, -1);

        int ans = 0;

        for(int i=1; i&amp;lt;=N; i++) {
            vis.clear();
            vis.resize(N+1);

            if(f(i)) ans++;
        }

        cout &amp;lt;&amp;lt; &quot;Case #&quot; &amp;lt;&amp;lt; t &amp;lt;&amp;lt; &quot;: &quot; &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 10532번 : Book Club&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N명의 사람들이 있고 M개의 순서쌍 (a, b)에 대해 a번 사람이 b번 사람의 책을 좋아한다고 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 사람이 책을 하나씩 전달받고 전달하여 순환이 가능한지 여부를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왼쪽에 N개의 노드, 오른쪽에 N개의 노드를 설정한 뒤 문제에서 제시한대로 M개의 간선을 연결하여 이분 그래프를 만들고 이분 매칭을 수행하여 최대 매치 수가 N인지의 여부를 파악해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666383472477&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

        int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

        adj.resize(N);

        while(M--) {
            int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

            adj[a].push_back(b);
        }

        l.resize(N, -1);
        r.resize(N, -1);

        int match = 0;

        for(int i=0; i&amp;lt;N; i++) {
            vis.clear();
            vis.resize(N);

            if(f(i)) match++;
        }

        if(match == N) cout &amp;lt;&amp;lt; &quot;YES\n&quot;;
        else cout &amp;lt;&amp;lt; &quot;NO\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 10850번 : Bounty Hunter&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;Platinum III&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노드가 N개인 단방향 그래프가 주어질 때, 한 사람이 하나의 경로로 지나간 노드들을 체크하되 한 사람이 지나간 노드는 다른 사람이 지나갈 수 없다고 할 때, 모든 노드들을 체크하기 위해 필요한 최소 인원 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 문제와 똑같이 왼쪽에 N개 노드, 오른쪽에도 N개 노드를 구성한 뒤 a &amp;rarr; b간선의 방향대로 왼쪽 a번 노드를 오른쪽 b번 노드로 연결한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 만들어진 이분 그래프에 대해 이분 매칭을 수행하여 최대 매칭을 찾는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이분 매칭을 통해 선택된 하나의 간선은 한 사람의 한 번의 이동으로 고려할 수 있고, 간선이 두 개 이상의 노드를 공유하지 않으므로 이들은 경로가 겹치지 않는 최대 이동에 해당한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 N - 최대 매치 수를 답으로 얻어주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666383956955&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

        int N; cin &amp;gt;&amp;gt; N;

        adj.resize(N);

        for(int i=0; i&amp;lt;N; i++) {
            int M; cin &amp;gt;&amp;gt; M;

            while(M--) {
                int x; cin &amp;gt;&amp;gt; x;

                adj[i].push_back(x);
            }
        }

        l.resize(N, -1);
        r.resize(N, -1);

        int match = 0;

        for(int i=0; i&amp;lt;N; i++) {
            vis.clear();
            vis.resize(N);

            if(f(i)) match++;
        }

        int ans = N - match;

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 17238번 : Delicious Pineapple Pizza&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭, 이분 탐색&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;길이 N인 수열 A와 B가 주어질 때, N개의 쌍을 만들어 a ^ b 값의 최솟값이 최대가 되도록 매칭하고, 그 때의 최솟값을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이분 매칭으로 값들을 매칭시켜야 하는 것은 쉽게 생각할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이분 탐색을 이용하여 특정 임계값 이상의 연산 값을 가지는 경우만 간선으로 연결하여 이분 매칭을 수행하고, 최대 매칭 값이 N이면 임계값을 증가시키는 방식으로 최솟값의 최댓값을 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666403468361&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;int&amp;gt; v(N), u(N);
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; u[i];

    int ll = 0, rr = INT_MAX, ans = 0;

    while(ll &amp;lt;= rr) {
        int m = (ll + rr) / 2;

        adj.clear();
        adj.resize(N);

        for(int i=0; i&amp;lt;N; i++)
            for(int j=0; j&amp;lt;N; j++)
                if((v[i] ^ u[j]) &amp;gt;= m) adj[i].push_back(j);

        l.clear();
        l.resize(N, -1);

        r.clear();
        r.resize(N, -1);

        int match = 0;

        for(int i=0; i&amp;lt;N; i++) {
            vis.clear();
            vis.resize(N);

            if(f(i)) match++;
        }

        if(match == N) {
            ans = max(ans, m);
            ll = m + 1;
        }
        else rr = m - 1;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 13503번 : 최소 체인 커버&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단방향 그래프가 주어질 때, 서로 겹치지 않는 몇 개의 경로로 모든 정점을 지나가려고 할 때 필요한 최소 경로의 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이분 매칭으로 최대 매칭 수를 구한 뒤, 정점의 수에서 매칭 수를 빼주면 곧 경로의 수가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666472487517&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    adj.resize(N+1);

    while(M--) {
        int x, y; cin &amp;gt;&amp;gt; x &amp;gt;&amp;gt; y;

        adj[x].push_back(y);
    }

    l.resize(N+1, -1);
    r.resize(N+1, -1);

    int match = 0;

    for(int i=1; i&amp;lt;=N; i++) {
        vis.clear();
        vis.resize(N+1);

        if(f(i)) match++;
    }

    int ans = N - match;

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/알고리즘 공부 내용 정리</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/634</guid>
      <comments>https://restudycafe.tistory.com/634#entry634comment</comments>
      <pubDate>Thu, 20 Oct 2022 20:08:51 +0900</pubDate>
    </item>
    <item>
      <title>이분 매칭 (Bipartite Matching) 문제 풀이 모음 221019</title>
      <link>https://restudycafe.tistory.com/633</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이분 매칭 알고리즘에 대해서는 이전에 다룬 적도 있고 문제 풀이도 한 적 있지만 잊어버린 내용이 많아서 공부를 위해 다시 정리해본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;이분 매칭 알고리즘&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. &lt;b&gt;이분 그래프&lt;/b&gt;란 그래프의 정점을 같은 그룹의 노드 사이에 간선으로 연결된 노드 쌍이 존재하지 않도록 두 그룹으로 나눌 수 있는 그래프를 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. &lt;b&gt;이분 매칭 알고리즘&lt;/b&gt;은 이러한 이분 그래프에서 하나의 노드가 두 개 이상의 간선에 포함되지 않도록 선택할 수 있는 최대 간선의 수를 말한다. (즉, 최대한으로 매칭시킬 수 있는 노드 쌍의 수를 찾는 것이다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. &lt;b&gt;쾨니그의 정리&lt;/b&gt;는 &lt;span style=&quot;color: #ee2323;&quot;&gt;최대 매칭 수 = 최소 꼭짓점 덮개 수&lt;/span&gt;라는 정리이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &lt;b&gt;최소 꼭짓점 덮개&lt;/b&gt;란 몇 개의 &lt;u&gt;노드를 선택하여 이들과 이 꼭짓점들을 포함하는 간선들을 체크할 때, 모든 간선들이 체크되도록 하는 최소 꼭짓점들의 개수&lt;/u&gt;를 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쾨니그의 정리는 이분 매칭 알고리즘 문제의 일부 상황에 적용이 가능한데, 예를 들어 이분 그래프 상황에서 최소 선택을 통해 모든 간선들이 선택되도록 해야할 때 이 최소 선택 수 = 최대 매칭 수임을 이용하여 그냥 이분 매칭 알고리즘을 돌려서 답을 얻으면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 1867번 : 돌멩이 제거&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N x N 격자에 M개의 돌이 있을 때, 한 번의 연산에서 행 또는 열을 선택하여 그 행이나 열에 있는 돌멩이를 모두 제거할 때, 격자의 모든 돌멩이를 제거하는 최소 연산 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 행의 번호를 left 노드, 열의 번호를 right 노드라고 할 때, 하나의 돌멩이는 하나의 행과 열을 연결하는 간선으로 나타낼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 하나의 간선은 하나의 행과 열을 이으므로 (행과 행 사이 간선, 열과 열 사이 간선은 당연히 존재하지 않으므로) 이분 그래프가 되고, 최소 노드를 선택하여 모든 간선이 선택되도록 하는 문제로 바뀐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 위의 쾨니그의 정리를 사용하여 최대 매칭을 구해주면 그것이 곧 최소 연산 수임을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 이분 매칭 알고리즘을 통해 최대 매칭 수를 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666119108130&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    vector&amp;lt;vector&amp;lt;char&amp;gt;&amp;gt; v(N+1, vector&amp;lt;char&amp;gt;(M+1));

    for(int i=1; i&amp;lt;=N; i++)
        for(int j=1; j&amp;lt;=M; j++) cin &amp;gt;&amp;gt; v[i][j];

    adj.resize(N+1);

    while(M--) {
        int x, y; cin &amp;gt;&amp;gt; x &amp;gt;&amp;gt; y;

        adj[x].push_back(y);
    }

    l.resize(N+1, -1);
    r.resize(N+1, -1);

    int ans = 0;

    for(int i=1; i&amp;lt;=N; i++) {
        vis.clear();
        vis.resize(N+1);

        if(f(i)) ans++;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 2414번 : 게시판 구멍 막기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N x M 크기의 격자에 . 또는 * 문자들이 주어지고, 행 또는 열 내에서 같은 방향으로 연속한 * 문자들을 선택할 수 있다고 할 때, 모든 *들이 선택되는 최소 선택 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가로 방향으로 연속한 *들에 번호를 매기고, 세로 방향으로 연속한 *들에 다시 번호를 매긴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 하나의 * 문자는 가로 번호와 세로 번호 하나씩을 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 가로 번호 또는 세로 번호를 선택한다는 것은 그 번호에 소속된 모든 *들을 선택한다고 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최소 가로 또는 세로 노드의 선택을 통해 모든 *들을 선택하면 문제가 해결된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것은 쾨니그의 정리에 의해 최대 매칭 수와 같으므로 위에서 가로 번호와 세로 번호를 하나의 *이 간선으로 연결된다고 할 때 최대 매칭 수를 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666124943077&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    vector&amp;lt;vector&amp;lt;char&amp;gt;&amp;gt; v(N+1, vector&amp;lt;char&amp;gt;(M+1));

    for(int i=1; i&amp;lt;=N; i++)
        for(int j=1; j&amp;lt;=M; j++) cin &amp;gt;&amp;gt; v[i][j];

    vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; u(N+1, vector&amp;lt;int&amp;gt;(M+1));
    int rnum = 1;

    for(int i=1; i&amp;lt;=N; i++)
        for(int j=1; j&amp;lt;=M; j++)
            if(v[i][j] == '*') {
                u[i][j] = rnum;

                if(j == M || v[i][j+1] == '.') rnum++;
            }

    rnum--;

    vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; w(N+1, vector&amp;lt;int&amp;gt;(M+1));
    int cnum = 1;

    for(int i=1; i&amp;lt;=M; i++)
        for(int j=1; j&amp;lt;=N; j++)
            if(v[j][i] == '*') {
                w[j][i] = cnum;

                if(j == N || v[j+1][i] == '.') cnum++;
            }

    cnum--;

    adj.resize(rnum+1);

    for(int i=1; i&amp;lt;=N; i++)
        for(int j=1; j&amp;lt;=M; j++)
            if(v[i][j] == '*') adj[u[i][j]].push_back(w[i][j]);

    l.resize(rnum+1, -1);
    r.resize(cnum+1, -1);

    int ans = 0;

    for(int i=1; i&amp;lt;=rnum; i++) {
        vis.clear();
        vis.resize(rnum+1);

        if(f(i)) ans++;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 2188번 : 축사 배정&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;b&gt; &lt;span style=&quot;color: #009a87;&quot;&gt;Platinum IV&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N마리의 소가 M개의 축사 중 각각 들어가고 싶어하는 축사들의 번호가 다르다고 할 때, 하나의 축사에 한 마리의 소만 들어갈 수 있다면 최대 몇 마리의 소를 축사로 배정할 수 있는지 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이분 매칭을 사용하는 가장 대표적인 상황의 기본 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N마리의 소가 원하는 축사들의 번호로 간선을 만들어주고, 이분 매칭을 수행해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666125675747&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    adj.resize(N+1);

    for(int i=1; i&amp;lt;=N; i++) {
        int K; cin &amp;gt;&amp;gt; K;

        while(K--) {
            int x; cin &amp;gt;&amp;gt; x;

            adj[i].push_back(x);
        }
    }

    l.resize(N+1, -1);
    r.resize(M+1, -1);

    int ans = 0;

    for(int i=1; i&amp;lt;=N; i++) {
        vis.clear();
        vis.resize(N+1);

        if(f(i)) ans++;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 풀이 코드와 동일한 코드로 &lt;b&gt;백준 BOJ 11375번 : 열혈강호&lt;/b&gt; 문제를 통과할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 9576번 : 책 나눠주기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N권의 책을 M명의 학생들에게 한 명당 최대 1권씩 나눠준다고 하고, 각 학생은 a ~ b번 사이의 책을 원한다고 할 때, 최대로 나눠줄 수 있는 책의 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;i번째 학생에 대한 입력이 (a_i, b_i)일 때 a_i ~ b_i번 책에 해당하는 노드를 i번째 학생으로 연결시켜주는 과정을 모든 학생에 대해 반복하고, 이분 매칭을 수행해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666136850675&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    while(T--) {
        int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

        adj.clear();
        adj.resize(N+1);

        for(int i=1; i&amp;lt;=M; i++) {
            int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

            for(int j=a; j&amp;lt;=b; j++) {
                adj[j].push_back(i);
            }
        }

        l.clear();
        l.resize(N+1, -1);

        r.clear();
        r.resize(M+1, -1);

        int ans = 0;

        for(int i=1; i&amp;lt;=N; i++) {
            vis.clear();
            vis.resize(N+1);

            if(f(i)) ans++;
        }

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 1017번 : 소수 쌍&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 자연수들이 주어졌을 때, 이들을 2개씩 묶어서 합한 값이 모두 소수가 되도록 묶는 방법들 각각에서 첫 번째 수와 매칭되는 수들을 오름차순으로 출력하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 수에 대응되는 노드들을 만들고, N x (N - 1) / 2개의 쌍 중에서 합이 소수인 것들을 간선으로 연결한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 첫 번째 노드 수에 해당하는 노드를 간선들 중 하나를 선택하여 연결한 뒤, 이 상태에서 이분 매칭을 수행하는 과정을 여러 번 거쳐 가능한 모든 경우를 구하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 주의할 점은 동일한 노드가 left, right 모두에 있으므로 모두 매칭되었을 때 매칭의 수가 N/2가 아니라 N이 되어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666148275904&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    vector&amp;lt;bool&amp;gt; p(2001, true);
    p[1] = false;

    for(int i=2; i*i&amp;lt;=2000; i++)
        for(int j=2; i*j&amp;lt;=2000; j++) p[i*j] = false;

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;int&amp;gt; v(N);
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];

    adj.resize(N);

    for(int i=0; i&amp;lt;N; i++)
        for(int j=i+1; j&amp;lt;N; j++)
            if(p[v[i] + v[j]]) {
                adj[i].push_back(j);
                adj[j].push_back(i);
            }

    vector&amp;lt;int&amp;gt; u;

    for(int i=0; i&amp;lt;adj[0].size(); i++) {
        l.clear();
        l.resize(N, -1);

        r.clear();
        r.resize(N, -1);

        int x = adj[0][i];

        l[0] = x, r[x] = 0;

        int cnt = 1;

        for(int j=1; j&amp;lt;N; j++) {
            vis.clear();
            vis.resize(N);

            vis[0] = vis[x] = true;

            if(f(j)) cnt++;
        }

        if(cnt == N) u.push_back(v[x]);
    }

    if(u.size() == 0) {
        cout &amp;lt;&amp;lt; -1 &amp;lt;&amp;lt; &quot;\n&quot;;
        return 0;
    }

    sort(u.begin(), u.end());

    for(int i=0; i&amp;lt;u.size(); i++) cout &amp;lt;&amp;lt; u[i] &amp;lt;&amp;lt; &quot; &quot;;
    cout &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 2191번 : 들쥐의 탈출&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N마리의 들쥐와 M개의 굴의 위치가 2차원 좌표로 주어지고, 각 쥐는 S x V 이하의 거리에 있는 굴로만 들어갈 수 있을 때 굴로 들어가지 못하는 최소 들쥐의 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 조건식에 대해 O(NM) 시간에 거리를 체크하여 그래프를 구성해주고, 이분 매칭으로 최대 매칭을 찾아 N에서 빼주면 답이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666151628958&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { double x, y; };

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    double S, V; cin &amp;gt;&amp;gt; S &amp;gt;&amp;gt; V;

    vector&amp;lt;s&amp;gt; v(N), u(M);

    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i].x &amp;gt;&amp;gt; v[i].y;
    for(int i=0; i&amp;lt;M; i++) cin &amp;gt;&amp;gt; u[i].x &amp;gt;&amp;gt; u[i].y;

    adj.resize(N);

    for(int i=0; i&amp;lt;N; i++)
        for(int j=0; j&amp;lt;M; j++) {
            double x = sqrt(pow(v[i].x - u[j].x, 2) + pow(v[i].y - u[j].y, 2));

            if(x &amp;lt;= S * V) adj[i].push_back(j);
        }

    l.resize(N, -1);
    r.resize(M, -1);

    int ans = 0;

    for(int i=0; i&amp;lt;N; i++) {
        vis.clear();
        vis.resize(N);

        if(f(i)) ans++;
    }

    ans = N - ans;

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 4966번 : Cards&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;Platinum IV&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 카드와 M개의 카드가 주어질 때, 두 카드 더미에서 공약수가 1보다 큰 카드 쌍을 제거해나간다고 할 때, 제거할 수 있는 최대 카드 쌍의 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N과 M이 크지 않으므로, 가능한 모든 쌍에 대해 공약수를 조사하여 간선으로 연결해주고, 그렇게 만들어진 그래프에 이분 매칭을 수행해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666152104315&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    while(true) {
        int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;
        if(N == 0 &amp;amp;&amp;amp; M == 0) break;

        vector&amp;lt;int&amp;gt; v(N), u(M);

        for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];
        for(int i=0; i&amp;lt;M; i++) cin &amp;gt;&amp;gt; u[i];

        adj.clear();
        adj.resize(N);

        for(int i=0; i&amp;lt;N; i++)
            for(int j=0; j&amp;lt;M; j++)
                if(__gcd(v[i], u[j]) &amp;gt; 1) adj[i].push_back(j);

        l.clear();
        l.resize(N, -1);

        r.clear();
        r.resize(M, -1);

        int ans = 0;

        for(int i=0; i&amp;lt;N; i++) {
            vis.clear();
            vis.resize(N);

            if(f(i)) ans++;
        }

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 18138번 : 리유나는 세일러복을 좋아해&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 티셔츠와 M개의 세일러카라가 있을 때 카라의 폭이 티셔츠의 폭 w에 대해 w/2 ~ 3w/4 또는 w ~ 5w/4인 경우에만 하나의 세일러복을 만들 수 있다고 할 때, 만들 수 있는 최대 세일러복의 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 노드, M개의 노드를 이분하여 생각한 뒤 O(NM) 시간에 대해 탐색을 수행하여 세일러복을 만들 수 있는 조건에 해당하는 두 노드 사이만 간선으로 연결해주어 이분 매칭을 수행해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666223435282&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    vector&amp;lt;double&amp;gt; v(N), u(M);

    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];
    for(int i=0; i&amp;lt;M; i++) cin &amp;gt;&amp;gt; u[i];

    adj.resize(N);

    for(int i=0; i&amp;lt;N; i++)
        for(int j=0; j&amp;lt;M; j++)
            if((v[i]/2 &amp;lt;= u[j] &amp;amp;&amp;amp; u[j] &amp;lt;= v[i]*3/4) || (v[i] &amp;lt;= u[j] &amp;amp;&amp;amp; u[j] &amp;lt;= v[i]*5/4)) adj[i].push_back(j);

    l.resize(N, -1);
    r.resize(M, -1);

    int ans = 0;

    for(int i=0; i&amp;lt;N; i++) {
        vis.clear();
        vis.resize(N+1);

        if(f(i)) ans++;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 10276번 : Jewelry Exhibition&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N x M 격자 내에 실수형 좌표 K개가 주어지고, 하나의 레이저는 행 또는 열 중 [정수, 정수+1] 구간의 모든 좌표를 스캔 가능하다고 할 때, K개의 좌표가 모두 스캔되기 위한 최소 레이저 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정수 x에 대해 [x, x+1) 구간의 모든 점들을 정수 x로 내림하여 기록하면 &lt;b&gt;백준 BOJ 1867번 : 돌멩이 제거&lt;/b&gt; 문제의 상황과 동일해지므로 같은 방식으로 풀이하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666226952382&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    while(T--) {
        int N, M, K; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M &amp;gt;&amp;gt; K;

        adj.clear();
        adj.resize(N);

        while(K--) {
            double x, y; cin &amp;gt;&amp;gt; x &amp;gt;&amp;gt; y;

            adj[(int)x].push_back((int)y);
        }

        l.clear();
        l.resize(N, -1);

        r.clear();
        r.resize(M, -1);

        int ans = 0;

        for(int i=0; i&amp;lt;N; i++) {
            vis.clear();
            vis.resize(N+1);

            if(f(i)) ans++;
        }

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 11180번 : Paintball&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N명의 사람이 있고, M개의 쌍 (a, b)가 주어질 때, a번 사람과 b번 사람이 서로를 paintball로 쏠 수 있다고 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 사람이 정확히 하나의 paintball을 맞는 것이 가능한지 판별하고, 가능하다면 i번째 사람이 몇 번 사람을 쏘면 되는지 그 예시를 출력하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이분 매칭으로 풀이하되 a번 노드를 b번 노드로 연결해주고, b번 노드 또한 a번 노드로 연결해준다. (둘 중 누구라도 서로를 쏠 수 있으므로)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이분 매칭을 해준 뒤 최대 매칭 값이 N인 경우만 답으로 가능하고, 그렇지 않으면 Impossible을 출력해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매칭 값이 N인 경우는 l[i] 값들을 출력해주면 된다. (l[i] : i번째 left 노드에서 연결되어있는 right 노드의 번호)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666227728318&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    adj.resize(N+1);

    while(M--) {
        int x, y; cin &amp;gt;&amp;gt; x &amp;gt;&amp;gt; y;

        adj[x].push_back(y);
        adj[y].push_back(x);
    }

    l.resize(N+1, -1);
    r.resize(N+1, -1);

    int ans = 0;

    for(int i=1; i&amp;lt;=N; i++) {
        vis.clear();
        vis.resize(N+1);

        if(f(i)) ans++;
    }

    if(ans != N) {
        cout &amp;lt;&amp;lt; &quot;Impossible\n&quot;;
        return 0;
    }

    for(int i=1; i&amp;lt;=N; i++) cout &amp;lt;&amp;lt; l[i] &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 11432번 : Candy Bombers&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N명의 파일럿이 각각 M개의 비행기 중에서 운전 가능한 것이 다르다고 할 때, 최대로 운전할 수 있는 비행기의 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일럿과 비행기 그룹 간의 그래프를 형성하여 이분 매칭을 돌리면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666230455199&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    for(int t=1; t&amp;lt;=T; t++) {
        int M, N; cin &amp;gt;&amp;gt; M &amp;gt;&amp;gt; N;

        adj.clear();
        adj.resize(N+1);

        for(int i=1; i&amp;lt;=N; i++) {
            int K; cin &amp;gt;&amp;gt; K;

            while(K--) {
                int x; cin &amp;gt;&amp;gt; x;

                adj[i].push_back(x);
            }
        }

        l.clear();
        l.resize(N+1, -1);

        r.clear();
        r.resize(M+1, -1);

        int ans = 0;

        for(int i=1; i&amp;lt;=N; i++) {
            vis.clear();
            vis.resize(N+1);

            if(f(i)) ans++;
        }

        cout &amp;lt;&amp;lt; &quot;Data Set &quot; &amp;lt;&amp;lt; t &amp;lt;&amp;lt; &quot;:\n&quot;;
        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
        cout &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 11670번 : 초등 수학&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 매칭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 정수 쌍이 주어지고, 두 정수를 +, -, * 연산 중 하나로 연산하여 모든 연산 값들이 다르게 만드는 것이 가능한지를 구하고, 가능하다면 각 연산식을 모두 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해시맵을 사용하여 각 연산 값들이 중복되지 않게 노드를 형성하여 연결해주고, 이분 매칭을 수행해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 매칭이 모두 가능한 경우 연산 식을 복원해야 하는데, 이를 위해 map을 하나 더 선언해서 각 right 노드가 원래는 어떤 값을 가지고 있었는지를 연결시켜주어 마지막에 출력해주는 방식을 사용하면 구현이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1666233791913&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; l, r;
vector&amp;lt;bool&amp;gt; vis;

bool f(int x) {
    vis[x] = true;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(r[y] == -1 || (!vis[r[y]] &amp;amp;&amp;amp; f(r[y]))) {
            l[x] = y, r[y] = x;

            return true;
        }
    }

    return false;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    adj.resize(N);

    vector&amp;lt;pair&amp;lt;int, int&amp;gt;&amp;gt; v(N);
    map&amp;lt;int, int&amp;gt; m, rm;
    int cnt = 0;

    for(int i=0; i&amp;lt;N; i++) {
        int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

        v[i].first = a, v[i].second = b;

        if(m[a+b] == 0) m[a+b] = ++cnt;
        rm[m[a+b]] = a + b;
        adj[i].push_back(m[a+b]);

        if(m[a-b] == 0) m[a-b] = ++cnt;
        rm[m[a-b]] = a - b;
        adj[i].push_back(m[a-b]);

        if(m[a*b] == 0) m[a*b] = ++cnt;
        rm[m[a*b]] = a * b;
        adj[i].push_back(m[a*b]);
    }

    l.resize(N, -1);
    r.resize(cnt+1, -1);

    int match = 0;

    for(int i=0; i&amp;lt;N; i++) {
        vis.clear();
        vis.resize(N);

        if(f(i)) match++;
    }

    if(match != N) {
        cout &amp;lt;&amp;lt; &quot;impossible\n&quot;;
        return 0;
    }

    for(int i=0; i&amp;lt;N; i++) {
        int a = v[i].first, b = v[i].second;

        char ch;

        if(rm[l[i]] == a + b) ch = '+';
        else if(rm[l[i]] == a - b) ch = '-';
        else if(rm[l[i]] == a * b) ch = '*';

        cout &amp;lt;&amp;lt; a &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; ch &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; b &amp;lt;&amp;lt; &quot; = &quot; &amp;lt;&amp;lt; rm[l[i]] &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/알고리즘 공부 내용 정리</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/633</guid>
      <comments>https://restudycafe.tistory.com/633#entry633comment</comments>
      <pubDate>Wed, 19 Oct 2022 04:00:19 +0900</pubDate>
    </item>
    <item>
      <title>백준 BOJ 풀이 (IGRUS Newbie Programming Contest 일부 포함)</title>
      <link>https://restudycafe.tistory.com/632</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 25711번 : 인경산&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;누적 합&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2차원 좌표 상의 N개의 점이 주어지고, 어떤 인접한 구간의 두 점 사이를 이동할 때 필요한 에너지는 내리막길일 경우 거리에 해당, 평지일 경우 거리의 2배, 오르막길일 경우 거리의 3배라고 할 때 M개의 쿼리에 대해 두 지점 사이의 필요한 에너지들을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿼리 문제이므로 O(1)이나 O(log N)과 같이 짧은 시간에 쿼리를 처리할 수 있어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제에서는 누적 합을 이용하여, 맨 왼쪽 지점에서부터 특정 지점까지 이동하는데 필요한 에너지들의 목록을 구해둔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반대로, 맨 오른쪽 지점에서부터 특정 지점까지 이동하는데 필요한 에너지들의 목록도 구해둔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각의 값들은 위에서 정의한 식대로 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 왼쪽 i번 지점에서 오른쪽 j번 지점으로 이동하는데 필요한 에너지는 (i &amp;lt; j) u[j] - u[i]와 같이 O(1)에 구할 수 있고, 오른쪽 i번 지점에서 왼쪽 j번 지점으로 이동하는데 필요한 에너지 (i &amp;gt; j) 역시 w[j] - w[i]와 같이 구할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1664748310857&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { double x, y; };

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    vector&amp;lt;s&amp;gt; v(N);

    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i].x;
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i].y;

    vector&amp;lt;double&amp;gt; u(N), w(N);

    for(int i=1; i&amp;lt;N; i++) {
        if(v[i].y &amp;lt; v[i-1].y)
            u[i] = u[i-1] + sqrt(pow(v[i].x - v[i-1].x, 2) + pow(v[i].y - v[i-1].y, 2));
        else if(v[i].y == v[i-1].y)
            u[i] = u[i-1] + sqrt(pow(v[i].x - v[i-1].x, 2) + pow(v[i].y - v[i-1].y, 2)) * 2;
        else if(v[i].y &amp;gt; v[i-1].y)
            u[i] = u[i-1] + sqrt(pow(v[i].x - v[i-1].x, 2) + pow(v[i].y - v[i-1].y, 2)) * 3;
    }

    for(int i=N-2; i&amp;gt;=0; i--) {
        if(v[i].y &amp;lt; v[i+1].y)
            w[i] = w[i+1] + sqrt(pow(v[i].x - v[i+1].x, 2) + pow(v[i].y - v[i+1].y, 2));
        else if(v[i].y == v[i+1].y)
            w[i] = w[i+1] + sqrt(pow(v[i].x - v[i+1].x, 2) + pow(v[i].y - v[i+1].y, 2)) * 2;
        else if(v[i].y &amp;gt; v[i+1].y)
            w[i] = w[i+1] + sqrt(pow(v[i].x - v[i+1].x, 2) + pow(v[i].y - v[i+1].y, 2)) * 3;
    }

    cout &amp;lt;&amp;lt; fixed;
    cout.precision(4);

    while(M--) {
        int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

        if(a &amp;lt; b) cout &amp;lt;&amp;lt; u[b-1] - u[a-1] &amp;lt;&amp;lt; &quot;\n&quot;;
        else cout &amp;lt;&amp;lt; w[b-1] - w[a-1] &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 25708번 : 만남의 광장&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;누적 합&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N x M 크기의 정수 배열이 주어지고, 이들 중에서 가로와 세로로 2줄씩을 제거하여 도로를 만들 때, 도로 위에 써 있는 숫자들의 합에 네 도로가 감싸는 잔디의 개수를 더한 값의 최댓값을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네 도로를 결정할 때 가능한 모든 경우를 해보면 O(N^2 M^2)가 되는데, N과 M이 작아 이 정도까지는 돌아간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 도로 위에 써 있는 숫자들을 빨리 더하는 방법인데 이것은 N개의 도로와 M개의 도로에 대해 각각의 합을 미리 구해두면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간 복잡도는 위에서 언급한대로 O(N^2 M^2)이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1664748672227&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; v(N, vector&amp;lt;int&amp;gt;(M));

    for(int i=0; i&amp;lt;N; i++)
        for(int j=0; j&amp;lt;M; j++) cin &amp;gt;&amp;gt; v[i][j];

    vector&amp;lt;int&amp;gt; u(N), w(M);

    for(int i=0; i&amp;lt;N; i++)
        for(int j=0; j&amp;lt;M; j++) u[i] += v[i][j];

    for(int i=0; i&amp;lt;M; i++)
        for(int j=0; j&amp;lt;N; j++) w[i] += v[j][i];

    int ans = INT_MIN;

    for(int i=0; i&amp;lt;N; i++)
        for(int j=0; j&amp;lt;M; j++)
            for(int k=i+1; k&amp;lt;N; k++)
                for(int l=j+1; l&amp;lt;M; l++) {
                    int sum = u[i] + w[j] + u[k] + w[l]
                              - v[i][j] - v[k][l] - v[i][l] - v[k][j]
                              + (k-i-1) * (l-j-1);

                    ans = max(ans, sum);
                }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 25710번 : 점수 계산&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스 알고리즘&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1 ~ 999 사이의 수 10만개가 주어질 때, 두 정수를 곱하여 얻어진 수의 각 자릿수를 더해 얻을 수 있는 최댓값을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N이 10만 이하로 O(N^2)에 돌리면 시간 초과가 발생하지만, 1 ~ 999 사이의 수만 입력되므로 이들 중에서 존재하는 수들에 대해서만 검사해보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 할 경우 시간 복잡도는 O(1000^2)로 매우 작다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1664748534709&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;int&amp;gt; v(1000);
    for(int i=0; i&amp;lt;N; i++) {
        int x; cin &amp;gt;&amp;gt; x;
        v[x]++;
    }

    vector&amp;lt;int&amp;gt; u;
    for(int i=1; i&amp;lt;=999; i++) {
        if(v[i] == 1) u.push_back(i);
        else if(v[i] &amp;gt;= 2) {
            u.push_back(i);
            u.push_back(i);
        }
    }

    int ans = 0;

    for(int i=0; i&amp;lt;u.size(); i++)
        for(int j=i+1; j&amp;lt;u.size(); j++) {
            int tmp = u[i] * u[j];

            int sum = 0;

            while(tmp &amp;gt; 0) {
                sum += tmp % 10;
                tmp /= 10;
            }

            ans = max(ans, sum);
        }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 25709번 : 1 빼기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;그리디&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주어진 수에 대해, 가지고 있는 수에서 1을 빼거나 또는 어떤 자리가 1의 값을 가질 때 해당 자리를 지우는 연산을 거쳐 0으로 만들기 위해 필요한 최소 연산 횟수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선적으로 높은 자릿수에 있는 1을 먼저 지우고, 만약 1이 없다면 1을 감소시키는 연산을 반복하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1664748427234&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    int ans = 0;

    while(true) {
        if(N == 0) break;

        string tmp = to_string(N);
        int idx = -1;

        for(int i=0; i&amp;lt;tmp.length(); i++)
            if(tmp[i] == '1') {
                idx = i;
                break;
            }

        if(idx != -1) {
            tmp = tmp.substr(0, idx) + tmp.substr(idx+1, tmp.length()-(idx+1));

            N = 0;

            for(int i=0; i&amp;lt;tmp.length(); i++) N = N * 10 + tmp[i] - '0';
        }
        else N--;

        ans++;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 25706번 : 자전거 묘기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;DP&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 위치에서의 점프대의 높이에 해당하는 N개의 수가 주어졌을 때, 각 위치에서 시작했을 때 밟게 되는 칸의 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역순으로 dp에 값들을 저장하면서 뒤의 dp 값들을 참조하여 답을 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( i ) 만약 시작 칸의 점프대 높이가 0이라면 dp[i] = dp[i+1] + 1이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( ii ) 시작 칸에서 점프대를 밟고 이동한 위치가 끝 또는 그 이상일 경우 dp[i] = 1이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( iii ) 위의 두 경우가 아니라면 dp 값은 점프대를 밟고 이동한 위치에서의 dp 값 + 1이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1664749145223&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;int&amp;gt; v(N);
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];

    vector&amp;lt;int&amp;gt; u(N);
    u[N-1] = 1;

    for(int i=N-2; i&amp;gt;=0; i--) {
        if(v[i] == 0) u[i] = u[i+1] + 1;
        else if(i + v[i] + 1 &amp;gt;= N) u[i] = 1;
        else u[i] = u[i + v[i] + 1] + 1;
    }

    for(int i=0; i&amp;lt;N; i++) cout &amp;lt;&amp;lt; u[i] &amp;lt;&amp;lt; &quot; &quot;;
    cout &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 16980번 : Bitaro the Brave&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;누적 합&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N x M 문자 배열이 주어졌을 때, 왼쪽 위에는 'J', 오른쪽 위에는 'O', 왼쪽 아래에는 'I'인 직사각형의 개수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오른쪽 아래에서부터 왼쪽 위로 검사하면서 J가 나올 때마다 지금까지 오른쪽에 나타난 O의 개수와 아래에 나타난 I의 개수의 곱만큼을 답에 더해주는 과정을 반복하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1664734129463&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    vector&amp;lt;vector&amp;lt;char&amp;gt;&amp;gt; v(N, vector&amp;lt;char&amp;gt;(M));
    for(int i=0; i&amp;lt;N; i++)
        for(int j=0; j&amp;lt;M; j++) cin &amp;gt;&amp;gt; v[i][j];

    vector&amp;lt;int&amp;gt; u(M);
    int ans = 0;

    for(int i=N-1; i&amp;gt;=0; i--) {
        int x = 0;

        for(int j=M-1; j&amp;gt;=0; j--) {
            if(v[i][j] == 'J') ans += x * u[j];
            else if(v[i][j] == 'O') x++;
            else if(v[i][j] == 'I') u[j]++;
        }
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 2208번 : 보석 줍기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;DP&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;길이 N인 수열에서, 길이가 M 이상인 구간에 대해 최대 구간 합을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1407&quot; data-origin-height=&quot;965&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAZzL6/btrNwDRwdbk/xIgPorX2KYJGIlNdd7upK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAZzL6/btrNwDRwdbk/xIgPorX2KYJGIlNdd7upK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAZzL6/btrNwDRwdbk/xIgPorX2KYJGIlNdd7upK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAZzL6%2FbtrNwDRwdbk%2FxIgPorX2KYJGIlNdd7upK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;689&quot; height=&quot;473&quot; data-origin-width=&quot;1407&quot; data-origin-height=&quot;965&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 구간 합 배열을 만들어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 i = M, 최소 구간합은 0부터 검사하면서 0 ~ i까지의 구간 합에서 0 ~ i-M 구간의 최소 구간합을 빼주는 과정을 i에 대해 반복해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1664749085686&quot; class=&quot;arduino&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    vector&amp;lt;int&amp;gt; v(N+1);
    for(int i=1; i&amp;lt;=N; i++) {
        int x; cin &amp;gt;&amp;gt; x;

        v[i] = v[i-1] + x;
    }

    int ans = 0, Min = 0;

    for(int i=M; i&amp;lt;=N; i++) {
        Min = min(Min, v[i-M]);
        ans = max(ans, v[i] - Min);
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/알고리즘 공부 내용 정리</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/632</guid>
      <comments>https://restudycafe.tistory.com/632#entry632comment</comments>
      <pubDate>Mon, 3 Oct 2022 03:18:23 +0900</pubDate>
    </item>
    <item>
      <title>알고리즘 분할정복 거듭제곱, 투포인터 등 알고리즘 문제 풀이 221001</title>
      <link>https://restudycafe.tistory.com/631</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;풀이한 문제들 중에서 인상적인 문제만 몇 개 뽑아서 정리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 알고리즘은 무작위로 선정하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 25569번 : My뷰 꾸미기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;Platinum IV&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;조합론, 분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 (a, b)쌍에 대해 min(a, b) = c라고 할 때, (a C 1 x b C 1) + (a C 2 x b C 2) + ... + (a C c x b C c)의 합을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N과 a, b는 30만 이하이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 항을 팩토리얼과 분모는 페르마의 소정리 + 분할 정복을 이용한 거듭제곱으로 계산이 가능하나, 항이 매우 많아 시간 초과에 걸리게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우 항을 줄여주어야 하는데, (a C 1 x b C 1) + (a C 2 x b C 2) + ... + (a C c x b C c) = (a C 1 x b C b - 1) + (a C 2 x b C b - 2) + ... + (a C c x b C b - c) = ((a + b) C b) - 1이므로 (a+b개 중에 1 ~ b개를 고르는 경우의 합이니까) 하나의 컴비네이션 값만 계산해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1664616135535&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

int mod = 1e9 + 7;
vector&amp;lt;int&amp;gt; fac(6e5 + 1);

int fp(int ba, int ex) {
    int ret = 1;

    while(ex &amp;gt; 0) {
        if(ex % 2 == 1) ret = (ret * ba) % mod;

        ba = (ba * ba) % mod;
        ex /= 2;
    }

    return ret;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    fac[0] = 1;

    for(int i=1; i&amp;lt;=6e5; i++) fac[i] = (fac[i-1] * i) % mod;

    int N; cin &amp;gt;&amp;gt; N;

    int ans = 1;

    while(N--) {
        int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

        int c = min(a, b);

        int tmp = (fac[a+b] * fp(fac[c], mod - 2)) % mod;

        tmp = (tmp * fp(fac[a+b-c], mod - 2)) % mod;

        tmp = (tmp - 1 + mod) % mod;

        ans = (ans * tmp) % mod;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 20366번 : 같이 눈사람 만들래?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;투 포인터&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 정수 중에 4개를 선택하여 두 개, 두 개씩 짝지은 합의 차의 최소를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 떠올릴 수 있는 방법은 N C 2개를 고른 배열을 만들어 두 배열에서 이분 탐색을 하는 것인데, 이 경우 각 합에서 중복되는 원소가 포함되어 있는지를 알 방법이 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 N이 600 이하이므로, 이중 for문을 돌려주고 이 때 각 i와 j 사이에서 l, r에 대한 투 포인터 알고리즘을 사용하여 v[i] + v[j]와 v[l] + v[r]을 가지고 비교하여 답을 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최종 시간 복잡도는 O(N^3)이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1664616283005&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;int&amp;gt; v(N);
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];

    sort(v.begin(), v.end());

    int ans = LLONG_MAX;

    for(int i=0; i&amp;lt;N; i++)
        for(int j=i+3; j&amp;lt;N; j++) {
            int l = i+1, r = j-1;

            while(l &amp;lt; r) {
                int dif = abs((v[i] + v[j]) - (v[l] + v[r]));

                ans = min(ans, dif);

                if((v[l] + v[r]) &amp;lt; (v[i] + v[j])) l++;
                else r--;
            }
        }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 3090번 : 차이를 최소로&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 탐색, 그리디&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;Platinum III&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;길이 N인 수열에서 하나의 수를 골라 1만큼 감소시키는 비용이 1이라고 할 때, 비용을 M 이하로 하여 수열의 인접한 숫자간의 차이값을 최소로 했을 때의 배열을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인접한 수의 차이를 m 이하로 잡고 비용을 M 이하로 사용할 수 있는지 체크하면서 이분 탐색으로 풀이하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;m을 설정했으면 값들을 그리디하게 바꾸어주는 것이 최선이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 0에서부터 N-1까지 이동하면서 오른쪽 수가 m보다 많이 크다면 비용에 v[i+1] - (v[i] + m)을 더해주고 v[i+1] = v[i] + m으로 바꿔준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반대 방향 인접 값들도 마찬가지로 N-1에서 0까지 이동하면서 왼쪽 수가 m보다 많이 크다면 비용에 v[i-1] - (v[i] + m)을 더해주고 v[i-1] = v[i] + m으로 바꿔준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1664637721914&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    vector&amp;lt;int&amp;gt; v(N);
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];

    int l = 0, r = 1e9;
    vector&amp;lt;int&amp;gt; ans;

    while(l &amp;lt;= r) {
        int m = (l + r) / 2;

        vector&amp;lt;int&amp;gt; u(v);
        int sum = 0;

        for(int i=0; i&amp;lt;N-1; i++) {
            if(u[i] + m &amp;lt; u[i+1]) {
                sum += u[i+1] - (u[i] + m);
                u[i+1] = u[i] + m;
            }
        }

        for(int i=N-1; i&amp;gt;0; i--) {
            if(u[i] + m &amp;lt; u[i-1]) {
                sum += u[i-1] - (u[i] + m);
                u[i-1] = u[i] + m;
            }
        }

        if(sum &amp;lt;= M) {
            ans = u;
            r = m - 1;
        }
        else l = m + 1;
    }

    for(int i=0; i&amp;lt;ans.size(); i++) cout &amp;lt;&amp;lt; ans[i] &amp;lt;&amp;lt; &quot; &quot;;
    cout &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 2812번 : 크게 만들기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt; Gold III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;그리디, 스택&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N자리 수에서 M개의 수를 지워 만들 수 있는 가장 큰 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뭔가 코드포스에서 많이 나올 것 같은 유형의 문제라서 풀어보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빈 문자열에 N자리 수를 앞에서부터 하나씩 추가하다가 추가할 수가 문자열의 맨 뒷 문자보다 크다면 맨 뒷 문자를 지우고 추가해주는 과정을 반복하고, M을 1 줄여준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 이 과정이 끝나도 M이 0보다 크다면, 뒤의 M자리는 지워졌다고 생각하고 앞의 s.length() - M자리만 출력해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1664654776074&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    string str; cin &amp;gt;&amp;gt; str;

    string ans = &quot;&quot;;

    for(int i=0; i&amp;lt;str.length(); i++) {
        while(ans.length() &amp;gt; 0 &amp;amp;&amp;amp; str[i] &amp;gt; ans.back() &amp;amp;&amp;amp; M &amp;gt; 0) {
            ans.pop_back();
            M--;
        }

        ans += str[i];
    }

    ans = ans.substr(0, ans.length()-M);

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 5447번 : Stock Market&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 :&lt;span style=&quot;color: #ee2323;&quot;&gt; DP&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구간 합이 최대인 부분의 양 끝 주소를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단, 그러한 구간이 여러 개 있을 경우 시작 주소가 작은 것을 구해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DP를 이용한 구간 합 최대를 구하는 알고리즘 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이에 대해서는 이 블로그 카테고리의 알고리즘 구현 코드 모음에 정리되어 있으니 참고 바란다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1664615750393&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    while(T--) {
        int N; cin &amp;gt;&amp;gt; N;

        vector&amp;lt;int&amp;gt; v(N);
        for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];

        vector&amp;lt;int&amp;gt; dp(N), le(N);
        dp[0] = v[0];

        for(int i=1; i&amp;lt;N; i++) {
            if(dp[i-1] &amp;gt;= 0) {
                dp[i] = dp[i-1] + v[i];
                le[i] = le[i-1];
            }
            else {
                dp[i] = v[i];
                le[i] = i;
            }
        }

        int Max = INT_MIN, l, r;
        for(int i=0; i&amp;lt;N; i++)
            if(dp[i] &amp;gt; Max) {
                Max = dp[i];
                l = le[i] + 1;
                r = i + 1;
            }

        cout &amp;lt;&amp;lt; l &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; r &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 10892번 : Divide into triangle&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;기하학, 구성적&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2차원 좌표 평면 상의 3N개의 점이 주어지고, 이들 중 일직선 상에 있는 세 점이 없다고 할 때, 3개씩 N개의 쌍을 만들어 각 쌍의 점들의 삼각형이 서로 겹치지 않게 하는 조합을 구하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;y 좌표, x 좌표 순으로 정렬하여 (반대로 정렬해도 상관없음) 순서대로 3개씩 뽑아주면 절대로 겹치지 않음을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1664616414859&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { int x, y, n; };

bool cmp(s a, s b) {
    if(a.y != b.y) return a.y &amp;gt; b.y;
    else if(a.x != b.x) return a.x &amp;lt; b.x;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;s&amp;gt; v(N*3);
    for(int i=0; i&amp;lt;N*3; i++) {
        cin &amp;gt;&amp;gt; v[i].x &amp;gt;&amp;gt; v[i].y;

        v[i].n = i+1;
    }

    sort(v.begin(), v.end(), cmp);

    for(int i=0; i&amp;lt;N*3; i+=3)
        cout &amp;lt;&amp;lt; v[i].n &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; v[i+1].n &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; v[i+2].n &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 25694번 : Ramen&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;그리디&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;길이 N인 라면의 맛에 해당하는 배열이 주어지고, 2l &amp;le; n인 l에 대해 a_1 ~ a_l이 모두 0보다 크다면 이 구간을 오른쪽으로 접어서 값을 합칠 수 있다고 할 때, 하나의 면을 길이가 1인 면으로 접을 수 있는지 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;길이 l만큼 접는 경우 그 구간은 모두 양수여야 하므로, 이는 결국 길이 1씩 접으면서 그 숫자들이 양수인지 체크하는 것과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 길이 1씩 체크해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1664615880308&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    int cur = 0;
    bool check = true;

    while(N--) {
        int x; cin &amp;gt;&amp;gt; x;

        cur += x;

        if(cur &amp;lt;= 0 &amp;amp;&amp;amp; N &amp;gt; 0) check = false;
    }

    if(check) cout &amp;lt;&amp;lt; &quot;YES\n&quot;;
    else cout &amp;lt;&amp;lt; &quot;NO\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/알고리즘 공부 내용 정리</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/631</guid>
      <comments>https://restudycafe.tistory.com/631#entry631comment</comments>
      <pubDate>Sat, 1 Oct 2022 18:24:46 +0900</pubDate>
    </item>
    <item>
      <title>삼분 탐색 알고리즘 문제 풀이 모음 220926</title>
      <link>https://restudycafe.tistory.com/630</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;삼분 탐색 알고리즘&lt;/b&gt;(Ternary Search Algorithm)이란 말 그대로 구간에서 &lt;span style=&quot;color: #ee2323;&quot;&gt;1/3 지점과 2/3 지점의 함수값의 크기 비교를 기반으로 탐색&lt;/span&gt;을 해나가는 알고리즘이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이분 탐색 알고리즘은 그래프가 단조 증가 또는 단조 감소한다는 조건 하에서만 사용이 가능하지만, 삼분 탐색은 극값이 최대 1개 이하로 있는 모든 그래프에 대하여 사용 가능하다. (즉, 단순히 극값을 갖는 그래프 뿐만이 아닌 단조 증가, 감소 그래프에서도 사용이 가능하다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1개의 최솟값을 갖는 y = x^2 꼴의 그래프를 [l, r]의 구간에서 삼분 탐색하는 상황에 대해 생각해보자. (물론 극값을 구간에 포함하고 있다고 가정한다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;654&quot; data-origin-height=&quot;442&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c690NF/btrM9Q9U5r3/tGGpTU6lSSKmMkk25ptpM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c690NF/btrM9Q9U5r3/tGGpTU6lSSKmMkk25ptpM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c690NF/btrM9Q9U5r3/tGGpTU6lSSKmMkk25ptpM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc690NF%2FbtrM9Q9U5r3%2FtGGpTU6lSSKmMkk25ptpM1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;654&quot; height=&quot;442&quot; data-origin-width=&quot;654&quot; data-origin-height=&quot;442&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1/3 지점을 x = m1, 2/3 지점을 x = m2라고 하며, 우리는 극값의 x 좌표 x_min을 찾고자 한다. (그러면 f_min = f(x_min)으로 구할 수 있다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( i )&lt;b&gt; f(m1) &amp;gt; f(m2)&lt;/b&gt;일 경우, 최소한 &lt;u&gt;[l, m1] 구간에는 극값을 포함하지 않는다.&lt;/u&gt; 따라서&lt;span style=&quot;color: #ee2323;&quot;&gt; l = m1&lt;/span&gt;으로 옮겨준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( ii ) &lt;b&gt;f(m1) &amp;lt; f(m2)&lt;/b&gt;일 경우, 최소한 &lt;u&gt;[m2, r] 구간에는 극값을 포함하지 않는다.&lt;/u&gt; 따라서 &lt;span style=&quot;color: #ee2323;&quot;&gt;r = m2&lt;/span&gt;으로 옮겨준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 과정을 반복하면 구간이 수렴하고, 적절한 횟수만큼 반복을 시켜준 뒤 답을 도출해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 예제들을 풀어보면서 연습해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 11662번 : 민호와 강호&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;삼분 탐색&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;민호가 (v0.x, v0.y)에서 (v1.x, v1.y)로 일정한 속도로 걸어가고, 강호도 (v2.x, v2.y)에서 (v3.x, v3.y)로 일정한 속도로 걸어가며 두 사람은 각자의 시작점에서 동시에 출발하여 각자의 도착점에 동시에 도착한다고 할 때, 두 사람의 거리가 최소일 때의 그 거리를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 사람 사이의 거리 그래프가 극값을 1개 이하로 가지므로 삼분 탐색을 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 사람 사이의 거리를 매개 변수에 대해 나타낸 뒤, 거리의 최솟값을 찾아주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 t = 0 ~ 1 범위에서 민호의 위치를 나타내자면, &lt;span style=&quot;color: #ee2323;&quot;&gt;(tx2 + (1-t)x1, ty2 + (1-t)y1)&lt;/span&gt;으로 나타낼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 선분에 대한 방정식을 매개변수로 표현하는 건데 고등학교 1학년 과정에 있는 것으로 기억한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 t = 0 ~ 1 범위에서 삼분 탐색을 해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 사람들의 풀이를 보니 바로 거리를 구해주는 방식으로 했던데 나는 이 방법이 편했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1664221523214&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { double x, y; };

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    cout &amp;lt;&amp;lt; fixed;
    cout.precision(8);

    vector&amp;lt;s&amp;gt; v(4);
    for(int i=0; i&amp;lt;4; i++) cin &amp;gt;&amp;gt; v[i].x &amp;gt;&amp;gt; v[i].y;

    double l = 0, r = 1;

    for(int tr=1; tr&amp;lt;=1e5; tr++) {
        double m1 = (l*2 + r) / 3;
        double m2 = (l + r*2) / 3;

        double a = sqrt(pow((m1*v[1].x + (1-m1)*v[0].x) - (m1*v[3].x + (1-m1)*v[2].x), 2)
                        + pow((m1*v[1].y + (1-m1)*v[0].y) - (m1*v[3].y + (1-m1)*v[2].y), 2));
        double b = sqrt(pow((m2*v[1].x + (1-m2)*v[0].x) - (m2*v[3].x + (1-m2)*v[2].x), 2)
                        + pow((m2*v[1].y + (1-m2)*v[0].y) - (m2*v[3].y + (1-m2)*v[2].y), 2));

        if(tr == 1e5) {
            cout &amp;lt;&amp;lt; a &amp;lt;&amp;lt; &quot;\n&quot;;
            break;
        }
        else if(a &amp;lt; b) r = m2;
        else if(a &amp;gt; b) l = m1;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 8986번 : 전봇대&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;삼분 탐색&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1차원 선상에 위치한 N개의 전봇대 좌표가 주어질 때, 각각을 정수 좌표로 이동시켜 일정한 간격으로 만들기 위해 필요한 최소 이동 거리 합을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 N = 4이고 좌표가 0, 4, 6, 9라면 두 번째 전봇대를 1만큼 이동시켜 0, 3, 6, 9로 만들 수 있고, 이 때 답은 1이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전봇대 사이의 거리를 x라고 할 때, 전봇대의 총 이동 거리를 f(x)라고 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 y = f(x) 그래프는 아래로 볼록한 그래프를 구성한다. (상식적으로 중간에 최솟값이 있으니까 당연하다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 삼분 탐색을 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제가 위의 문제와 다른 점은 x가 정수 좌표에서만 정의가 된다는 것인데, 그래프의 개형 자체는 똑같으므로 비슷한 방식으로 풀어줄 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대신 여기서는 x가 정수에서만 정의됨을 활용하여 &lt;span style=&quot;color: #ee2323;&quot;&gt;탐색 종료 조건을 r - l &amp;lt; 3과 같이 설정해줄 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1664248085609&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;int&amp;gt; v(N);
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];

    int l = 0, r = v[N-1];
    int tr = 1e4;

    while(r - l &amp;gt;= 3) {
        int m1 = (l*2 + r) / 3;
        int m2 = (l + r*2) / 3;

        int s1 = 0;
        for(int i=0; i&amp;lt;N; i++) s1 += abs(m1*i - v[i]);

        int s2 = 0;
        for(int i=0; i&amp;lt;N; i++) s2 += abs(m2*i - v[i]);

        if(s1 &amp;lt; s2) r = m2;
        else if(s1 &amp;gt; s2) l = m1;
    }

    int ans = LLONG_MAX;

    for(int i=l; i&amp;lt;=r; i++) {
        int sum = 0;
        for(int j=0; j&amp;lt;N; j++) sum += abs(i*j - v[j]);

        ans = min(ans, sum);
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 11664번 : 선분과 점&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;삼분 탐색&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3차원 좌표평면 상에서 선분과 점 사이의 최소 거리를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;벡터를 사용해서 풀어도 되고, 삼분 탐색을 이용해서 풀어도 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서는 삼분 탐색을 연습하고 있으니 삼분 탐색으로 풀어보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 BOJ 11662와 마찬가지로, 매개변수를 이용하여 t = 0 ~ 1으로 선분의 내분점을 잡을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 선분 위의 내분점과 점 사이의 거리를 이용하여 삼분 탐색을 해주면 풀이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 f(m1) = f(m2)인 경우가 나올 수 있으므로 해당 경우에도 l = m1으로 옮기던가 r = m2로 옮기던가 둘 중 하나를 처리 해주어야 반례가 발생하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1664267479577&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { double x, y, z; };

double f(s a, s b) {
    return sqrt(pow(a.x - b.x, 2) + pow(a.y - b.y, 2) + pow(a.z - b.z, 2));
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    cout &amp;lt;&amp;lt; fixed;
    cout.precision(6);

    vector&amp;lt;s&amp;gt; v(3);
    for(int i=0; i&amp;lt;3; i++)
        cin &amp;gt;&amp;gt; v[i].x &amp;gt;&amp;gt; v[i].y &amp;gt;&amp;gt; v[i].z;

    double l = 0, r = 1, tr = 1e3;

    while(tr--) {
        double m1 = (l*2 + r) / 3;
        double m2 = (l + r*2) / 3;

        double a = f({m1*v[1].x + (1-m1)*v[0].x, m1*v[1].y + (1-m1)*v[0].y, m1*v[1].z + (1-m1)*v[0].z}, v[2]);
        double b = f({m2*v[1].x + (1-m2)*v[0].x, m2*v[1].y + (1-m2)*v[0].y, m2*v[1].z + (1-m2)*v[0].z}, v[2]);

        if(tr == 0) cout &amp;lt;&amp;lt; a &amp;lt;&amp;lt; &quot;\n&quot;;
        else if(a &amp;gt; b) l = m1;
        else r = m2;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 13011번 : 사탕의 밀도&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;삼분 탐색&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N명의 학생이 있고 각 바구니의 용량은 v[i], 원하는 사탕의 무게는 u[i]일 때 모든 학생들에게 동일한 밀도의 사탕을 줄 때 밀도를 얼마로 해야 각 참가자가 원하는 무게와 실제 무게의 차이가 최소가 되는지를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;밀도를 먼저 가정하고 차이를 구한 뒤, 그 차이값에 따라 탐색 범위를 조정하는 삼분 탐색으로 풀이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무게 차이에 대한 연산을 여러 번 해야하기 때문에, 함수로 따로 빼서 구현하는 편이 나은 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1664331955806&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

double f(vector&amp;lt;double&amp;gt; v, vector&amp;lt;double&amp;gt; u, double m) {
    double sum = 0;

    for(int i=0; i&amp;lt;v.size(); i++)
        sum += abs(v[i] * m - u[i]);

    return sum;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    cout &amp;lt;&amp;lt; fixed;
    cout.precision(9);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;double&amp;gt; v(N), u(N);
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; u[i];

    double l = 0, r = 1e6;
    double Min = INT_MAX, tr = 1e3;

    while(tr--) {
        double m1 = (l*2 + r) / 3;
        double m2 = (l + r*2) / 3;

        double a = f(v, u, m1);
        double b = f(v, u, m2);

        if(tr == 0) cout &amp;lt;&amp;lt; a &amp;lt;&amp;lt; &quot;\n&quot;;
        else if(a &amp;gt; b) l = m1;
        else r = m2;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 3855번 : Trick or Treat&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;삼분 탐색&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우연인지 모르겠지만 이 문제도 사탕과 관련된 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개 지점의 (x,y) 좌표가 주어지고, y = 0 직선 위의 하나의 x 좌표를 잡아서 가장 먼 지점의 거리가 최소가 되게 할 때, 그 x 좌표를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 먼 거리가 최소가 되는 지점이 있으므로, 그래프는 아래로 볼록하므로 삼분 탐색을 이용해서 풀이 가능함을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;x 좌표의 범위를 설정하고 그 범위 내에서 삼분 탐색을 수행해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1664332796741&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { double x, y; };

double f(vector&amp;lt;s&amp;gt; v, double m) {
    double Max = 0;

    for(int i=0; i&amp;lt;v.size(); i++)
        Max = max(Max, sqrt(pow(v[i].x - m, 2) + pow(v[i].y, 2)));

    return Max;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    cout &amp;lt;&amp;lt; fixed;
    cout.precision(5);

    while(true) {
        int N; cin &amp;gt;&amp;gt; N;
        if(N == 0) break;

        vector&amp;lt;s&amp;gt; v(N);
        for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i].x &amp;gt;&amp;gt; v[i].y;

        double l = -2e5, r = 2e5, tr = 1e2;

        while(tr--) {
            double m1 = (l*2 + r) / 3;
            double m2 = (l + r*2) / 3;

            double a = f(v, m1);
            double b = f(v, m2);

            if(tr == 0) cout &amp;lt;&amp;lt; l &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; a &amp;lt;&amp;lt; &quot;\n&quot;;
            else if(a &amp;gt; b) l = m1;
            else r = m2;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 21618번 : Lunch Concert&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;삼분 탐색&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N명의 사람이 1차원 좌표 상에 있고, 각 사람의 위치와 단위 거리 1만큼을 이동하는데 걸리는 시간, 소리를 들을 수 있는 반경이 주어질 때 어떤 좌표에서 공연을 해야 모든 사람들이 공연을 듣는데 필요한 이동 시간의 합이 최소가 되는지를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 이동 시간의 합을 구하는 것은 어렵지 않고, 이를 함수로 만들어 둔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이동 시간의 합이 최소가 되는 위치를 기준으로 양방향으로 멀어질수록, 이동 시간의 합이 커짐을 알 수 있고 따라서 그래프는 아래로 볼록한 개형을 가지며 삼분 탐색을 사용하여 풀이할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1664332844783&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { int x, t, r; };

int f(vector&amp;lt;s&amp;gt; v, int m) {
    int sum = 0;

    for(int i=0; i&amp;lt;v.size(); i++) {
        if(v[i].x - v[i].r &amp;lt;= m &amp;amp;&amp;amp; m &amp;lt;= v[i].x + v[i].r) continue;
        else if(m &amp;lt; v[i].x - v[i].r) sum += ((v[i].x - v[i].r) - m) * v[i].t;
        else if(m &amp;gt; v[i].x + v[i].r) sum += (m - (v[i].x + v[i].r)) * v[i].t;
    }

    return sum;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;s&amp;gt; v(N);
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i].x &amp;gt;&amp;gt; v[i].t &amp;gt;&amp;gt; v[i].r;

    int l = 0, r = 1e9, tr = 1e2;

    while(tr--) {
        int m1 = (l*2 + r) / 3;
        int m2 = (l + r*2) / 3;

        int a = f(v, m1);
        int b = f(v, m2);

        if(a &amp;gt; b) l = m1;
        else r = m2;
    }

    int m = (l + r) / 2;
    int ans = f(v, m);

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 12742번, 12743번 : 혼합물 (Small), (Large)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;삼분 탐색&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A를 단위 질량만큼 만들기 위해 A_1 ~ A_N이 각각 v[i]만큼 필요하거나, 또는 B를 단위 질량만큼 만들기 위해 B_1 ~ B_N이 각각 u[i]만큼 필요하다고 할 때 A의 단위 질량 당 가격은 M이고 B의 단위 질량당 가격은 K일 때 최대로 만들 수 있는 물질의 비용과, 그 때 각 물질을 얼만큼씩 만들어야 하는지를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 A를 만들 수 있는 최대 양 r을 찾고, l = 0일 때 [l, r] 범위 내에서 A를 만들고 나머지로 B를 최대한 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 만들어진 물질의 비용을 구할 수 있으며, 이 비용에 따라 삼분 탐색을 수행해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;small, large 두 버전 모두 동일한 알고리즘으로 풀린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1664380914782&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

int N;
double M, K;
vector&amp;lt;double&amp;gt; v, u, w;
struct s { double a, b, c; };

s f(double m) {
    double Min = LLONG_MAX;

    for(int i=0; i&amp;lt;N; i++)
        Min = min(Min, (w[i] - m * v[i]) / u[i]);

    return {m * M + Min * K, m, Min};
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    cout &amp;lt;&amp;lt; fixed;
    cout.precision(2);

    cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M &amp;gt;&amp;gt; K;

    v.resize(N);
    u.resize(N);
    w.resize(N);

    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; u[i];
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; w[i];

    double l = 0, r = LLONG_MAX, tr = 1e2;

    for(int i=0; i&amp;lt;N; i++) r = min(r, w[i] / v[i]);

    while(tr--) {
        double m1 = (l*2 + r) / 3;
        double m2 = (l + r*2) / 3;

        if(f(m1).a &amp;lt; f(m2).a) l = m1;
        else r = m2;
    }

    double m = (l + r) / 2;

    cout &amp;lt;&amp;lt; f(m).a &amp;lt;&amp;lt; &quot;\n&quot;;
    cout &amp;lt;&amp;lt; f(m).b &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; f(m).c &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 8983번 : 사냥꾼&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;삼분 탐색&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;x축 위에 N개의 사대가 있고, M개의 동물들의 좌표 (a, b)가 주어진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사대와 동물 (a, b) 사이의 거리를 |x - a| + b라고 할 때, 거리가 K 이내인 모든 동물을 사냥할 수 있다고 한다면 한 개 이상의 사대에 대해 사정 거리 이내에 있는 동물들의 개수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 동물에 대해 사정 거리 이내에 있는지를, 가장 거리가 가까운 사대를 찾기 위해 삼분 탐색을 사용하여 풀 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 가까운 사대를 찾았으면 그 사대와의 맨해튼 거리가 K 이내인지 체크하여 counting 해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1664381658482&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M, K; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M &amp;gt;&amp;gt; K;

    vector&amp;lt;int&amp;gt; v(N);
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];

    sort(v.begin(), v.end());

    int ans = 0;

    while(M--) {
        int x, y; cin &amp;gt;&amp;gt; x &amp;gt;&amp;gt; y;

        int l = 0, r = N-1, tr = 1e2;

        while(tr--) {
            int m1 = (l*2 + r) / 3;
            int m2 = (l + r*2) / 3;

            int d1 = abs(x - v[m1]) + y;
            int d2 = abs(x - v[m2]) + y;

            if(d1 &amp;gt; d2) l = m1;
            else r = m2;
        }

        bool check = false;

        for(int i=l; i&amp;lt;=r; i++)
            if(abs(x - v[i]) + y &amp;lt;= K) check = true;

        if(check) ans++;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 1087번 : 쥐 잡기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;삼분 탐색&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 점의 좌표와 이동 속도가 주어질 때, 어떤 시점에서도 N개의 점이 하나의 정사각형의 내부에 동시에 포함되지 않도록 하는 가장 큰 정사각형의 한 변의 길이를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제를 바꿔 말하면 N개의 점을 (정사각형의 변 위의 점까지 포함하여) 포함하는 최소 정사각형의 한 변의 길이를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 시간 t일 때 점들의 x 좌표의 최대 최소 차이, y 좌표의 최대 최소 차이 중 큰 것을 삼분 탐색으로 구하면서 범위를 좁혀주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1664382309181&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { double x, y, vx, vy; };
vector&amp;lt;s&amp;gt; v;

double f(double m) {
    double xmin = INT_MAX, ymin = INT_MAX, xmax = INT_MIN, ymax = INT_MIN;

    for(int i=0; i&amp;lt;v.size(); i++) {
        xmin = min(xmin, v[i].x + v[i].vx * m);
        ymin = min(ymin, v[i].y + v[i].vy * m);
        xmax = max(xmax, v[i].x + v[i].vx * m);
        ymax = max(ymax, v[i].y + v[i].vy * m);
    }

    return max(xmax - xmin, ymax - ymin);
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    cout &amp;lt;&amp;lt; fixed;
    cout.precision(9);

    int N; cin &amp;gt;&amp;gt; N;

    v.resize(N);
    for(int i=0; i&amp;lt;N; i++)
        cin &amp;gt;&amp;gt; v[i].x &amp;gt;&amp;gt; v[i].y &amp;gt;&amp;gt; v[i].vx &amp;gt;&amp;gt; v[i].vy;

    double l = 0, r = 2e3, tr = 1e2;

    while(tr--) {
        double m1 = (l*2 + r) / 3;
        double m2 = (l + r*2) / 3;

        if(f(m1) &amp;gt; f(m2)) l = m1;
        else r = m2;
    }

    double m = (l + r) / 2;

    cout &amp;lt;&amp;lt; f(m) &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 17574번 : Jackpot&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;삼분 탐색&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 문 중 하나의 뒤에 상금이 있고, 상금은 문을 열 때마다 줄어들며, 초기 상금이 m이고 주어진 상수 값이 f일 때 d개의 문을 연 상태에서 남은 상금의 값 pr = m - (d * f)^2이라고 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예상 수익이 당첨 확률에 남은 상금을 곱한 값이라고 할 때 예상 수익을 극대화시키기 위해서는 문을 몇 개 연 상태에서 고르는 것이 최선인지를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제에서 하라는 대로 식을 구해주기만 하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;d개의 문을 열었을 때 당첨 확률은 1/(N - d)이므로, 예상 수익은 1/(N-d) x (m - (d x f)^2)이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것은 위로 볼록한 그래프 개형을 가지므로 (그려서 확인하지 않더라도 문제에서 준 &quot;최댓값&quot;을 구하라는 표현을 보면 극대값이 존재함을 예상할 수 있다.) 삼분 탐색으로 이를 찾아주기만 하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 주의할 점은 문을 모두 연 상태는 제외해야 하므로 (왜냐하면 문을 &quot;일부&quot; 열고 나서 최종 선택을 하는 것이므로) r = N-1로 두어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1664440770616&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

double N, M, K;

double f(double m) {
    return (1.0 / (N - m)) * (M - pow(m * K, 2));
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    cout &amp;lt;&amp;lt; fixed;
    cout.precision(6);

    cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M &amp;gt;&amp;gt; K;

    double l = 0, r = N-1, tr = 1e2;

    while(tr--) {
        double m1 = (l*2 + r) / 3;
        double m2 = (l + r*2) / 3;

        if(f(m1) &amp;lt; f(m2)) l = m1;
        else r = m2;
    }

    double m = (l + r) / 2;

    cout &amp;lt;&amp;lt; f(m) &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/알고리즘 공부 내용 정리</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/630</guid>
      <comments>https://restudycafe.tistory.com/630#entry630comment</comments>
      <pubDate>Tue, 27 Sep 2022 04:48:06 +0900</pubDate>
    </item>
    <item>
      <title>세그먼트 트리 문제 풀이 모음 220924</title>
      <link>https://restudycafe.tistory.com/629</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;백만년만에 문제 풀이 정리를 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1174&quot; data-origin-height=&quot;341&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cHIBMh/btrMVuNA6Yf/P2Fb2GYfFGWo5KHjTAOUUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cHIBMh/btrMVuNA6Yf/P2Fb2GYfFGWo5KHjTAOUUK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cHIBMh/btrMVuNA6Yf/P2Fb2GYfFGWo5KHjTAOUUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcHIBMh%2FbtrMVuNA6Yf%2FP2Fb2GYfFGWo5KHjTAOUUK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1174&quot; height=&quot;341&quot; data-origin-width=&quot;1174&quot; data-origin-height=&quot;341&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 시간 날 때마다 문제는 꾸준히 풀어오고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그동안 정리 안 한 것은 브론즈 문제들을 굳이 풀이를 정리하기에는 불필요하다고 느껴서였고, 가끔 약간의 메모가 필요한 문제들이 있으면 정리해보려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 8120번 : Coding of Permutations&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 :&lt;span style=&quot;color: #ee2323;&quot;&gt; 세그먼트 트리&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;길이 N인 수열로 a_i = i번째 위치의 왼쪽에 있는 더 큰 수의 개수가 주어질 때, N에 대한 순열을 찾는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 (0, 0, 1, 0, 2, 0, 4)가 주어진다면 (1, 5, 2, 6, 4, 7, 3)이 답인데 왜냐하면 1의 왼쪽에 더 큰 수가 0개, 5의 왼쪽에 더 큰 수가 0개, 2의 왼쪽에 더 큰 수가 1개, 6의 왼쪽에 더 큰 수가 0개, ...로 규칙을 만족하기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제의 경우에는 역순으로 체크해보면서 답을 구하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 4가 나왔다면, 1 ~ 7 중에서 4개의 더 큰 수를 갖는 3이 맨 오른쪽에 위치함을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 1 ~ 7의 목록에서 3을 지운다. (즉, {1, 2, 4, 5, 6, 7})&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 오른쪽에서 두 번째에 있는 수가 0이므로, 남은 수 중에서 0개의 더 큰 수를 갖는 7이 오른쪽에서 두 번째에 옴을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 식으로 풀어주면 되는데, 목록에서 수를 제거해야 하기 때문에 세그먼트 트리를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 트리에 1 ~ N의 위치에 수를 1씩 넣어주고, 순열 (0, 0, 1, 0, 2, 0, 4)를 벡터 u에 저장했다고 가정하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세그먼트 트리는 벡터 v에 구현되었다고 가정하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 v[1](= 루트 노드, 즉 트리의 현재 사이즈) - u[i]번째로 작은 원소를 출력하고 그것을 지워주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 u[i] &amp;ge; v[1]인 순간이 한 번이라도 있으면 그러한 순열은 존재하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1664026730914&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

int N, Max = 3e4 + 1;
vector&amp;lt;int&amp;gt; v(Max * 4);

void f(int n, int b, int e, int idx) {
    if(idx &amp;lt; b || e &amp;lt; idx) return;

    v[n]++;

    if(b == e) return;

    f(n*2, b, (b+e)/2, idx);
    f(n*2 + 1, (b+e)/2 + 1, e, idx);
}

int g(int n, int b, int e, int cnt) {
    v[n]--;

    if(b == e) return b;

    if(cnt &amp;lt;= v[n*2]) return g(n*2, b, (b+e)/2, cnt);
    else return g(n*2 + 1, (b+e)/2 + 1, e, cnt - v[n*2]);
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    cin &amp;gt;&amp;gt; N;

    for(int i=1; i&amp;lt;=N; i++) f(1, 1, Max, i);

    vector&amp;lt;int&amp;gt; u(N+1);
    for(int i=1; i&amp;lt;=N; i++) cin &amp;gt;&amp;gt; u[i];

    vector&amp;lt;int&amp;gt; ans(N+1);
    for(int i=N; i&amp;gt;=1; i--) {
        if(u[i] &amp;gt;= v[1]) {
            cout &amp;lt;&amp;lt; &quot;NIE\n&quot;;
            return 0;
        }

        ans[i] = g(1, 1, Max, v[1] - u[i]);
    }

    for(int i=1; i&amp;lt;=N; i++) cout &amp;lt;&amp;lt; ans[i] &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 15459번 : Haybale Feast&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;세그먼트 트리, 두 포인터&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;길이 N인 수열 A, B에 대해 연속한 부분 수열을 골라 a_l ~ a_r 값이 M 이상인 것들 중 b_l ~ b_r 중 최댓값이 최소가 되도록하는 값을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;수열 B에 대해 구간의 최솟값을 다루는 세그먼트 트리&lt;/span&gt;를 만들고, &lt;span style=&quot;color: #ee2323;&quot;&gt;수열 A에 대해 투 포인터 알고리즘&lt;/span&gt;을 써주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;항상 느끼지만 USACO에 정석적이고 좋은 문제가 많은 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1664032978218&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;int&amp;gt; v, w;

int init(int n, int b, int e) {
    if(b == e) return v[n] = w[b];

    int lv = init(n*2, b, (b+e)/2);
    int rv = init(n*2 + 1, (b+e)/2 + 1, e);

    return v[n] = max(lv, rv);
}

int f(int n, int b, int e, int l, int r) {
    if(r &amp;lt; b || e &amp;lt; l) return INT_MIN;
    if(l &amp;lt;= b &amp;amp;&amp;amp; e &amp;lt;= r) return v[n];

    int lv = f(n*2, b, (b+e)/2, l, r);
    int rv = f(n*2 + 1, (b+e)/2 + 1, e, l, r);

    return max(lv, rv);
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    vector&amp;lt;int&amp;gt; u(N+1);
    w.resize(N+1);

    for(int i=1; i&amp;lt;=N; i++) {
        int x; cin &amp;gt;&amp;gt; x &amp;gt;&amp;gt; w[i];

        u[i] = u[i-1] + x;
    }

    v.resize(N*4);
    init(1, 1, N);

    int i = 1, j = 1, ans = INT_MAX;

    while(j &amp;lt;= N) {
        int sum = u[j] - u[i-1];

        if(sum &amp;lt; M) j++;
        else {
            ans = min(ans, f(1, 1, N, i, j));

            i++;
            if(i &amp;gt; j) j = i;
        }
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 12803번 : Peter and the Textbook&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt; Silver II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;세그먼트 트리&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1 ~ N 페이지로 구성된 책이 있고 x번째 페이지를 제거한다면 같이 제본된 N-x+1번째 페이지도 같이 제거된다고 할 때, 두 가지의 쿼리를 처리하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. - x : x번째 페이지와 N-x+1번째 페이지를 제거한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. ? x : 현재 남은 페이지 중에 앞에서부터 x번째 페이지의 번호를 출력한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N이 매우 작으므로 세그먼트 트리를 쓸 필요는 없지만, 세그먼트 트리의 연습을 위해 세그트리로 문제를 풀어보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 1 ~ N번째 리프 노드에 대해 모두 1로 채워주고, 그 다음 - 쿼리에 대해서는 루트 노드에서부터 1씩 감소시켜가면서 리프 노드까지 값을 처리해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 ? 쿼리에 대해서는 왼쪽 자식의 값이 cnt 값보다 큰지 작은지를 판단하여 내려가는 방향을 달리해주어 탐색해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1664027841727&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

int Max = 1e2 + 1;
vector&amp;lt;int&amp;gt; v;

void f(int n, int b, int e, int idx) {
    if(idx &amp;lt; b || e &amp;lt; idx) return;

    v[n]++;

    if(b == e) return;

    f(n*2, b, (b+e)/2, idx);
    f(n*2 + 1, (b+e)/2 + 1, e, idx);
}

void g(int n, int b, int e, int idx) {
    if(idx &amp;lt; b || e &amp;lt; idx) return;

    v[n]--;

    if(b == e) return;

    g(n*2, b, (b+e)/2, idx);
    g(n*2 + 1, (b+e)/2 + 1, e, idx);
}

int h(int n, int b, int e, int cnt) {
    if(b == e) return b;

    if(cnt &amp;lt;= v[n*2]) return h(n*2, b, (b+e)/2, cnt);
    else return h(n*2 + 1, (b+e)/2 + 1, e, cnt - v[n*2]);
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    while(T--) {
        v.clear();
        v.resize(Max*4);

        int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

        for(int i=1; i&amp;lt;=N; i++) f(1, 1, Max, i);

        while(M--) {
            char Q; cin &amp;gt;&amp;gt; Q;
            int x; cin &amp;gt;&amp;gt; x;

            if(Q == '-') {
                g(1, 1, Max, x);
                g(1, 1, Max, N-x+1);
            }
            else if(Q == '?') cout &amp;lt;&amp;lt; h(1, 1, Max, x) &amp;lt;&amp;lt; &quot;\n&quot;;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 2104번 : 부분배열 고르기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;세그먼트 트리&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;길이 N인 수열이 주어질 때 연속하는 부분 수열을 골라 그 점수가 (v[l] + v[l+1] + ... + v[r]) * min(v[l] ~ v[r])이라고 할 때 점수의 최댓값을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백준 BOJ 6549번 : 히스토그램에서 가장 큰 직사각형 문제를 떠올려보면 같은 방법으로 풀이가 가능하다는 것을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 여기서는 직사각형의 넓이가 아닌 다른 점수를 사용하므로, v[l] + ... + v[r] 값을 누적 합 배열을 사용하여 w[r] - w[l-1]로 O(1)에 구할 수 있고, 이를 활용하여 점수 값을 비교하여 최댓값을 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1664029486241&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

int N;
vector&amp;lt;int&amp;gt; v, u, w;

int init(int n, int b, int e) {
    if(b == e) return u[n] = b;

    int lv = init(n*2, b, (b+e)/2);
    int rv = init(n*2 + 1, (b+e)/2 + 1, e);

    if(v[lv] &amp;lt; v[rv]) return u[n] = lv;
    else return u[n] = rv;
}

int g(int n, int b, int e, int l, int r) {
    if(r &amp;lt; b || e &amp;lt; l) return -1;
    if(l &amp;lt;= b &amp;amp;&amp;amp; e &amp;lt;= r) return u[n];

    int lv = g(n*2, b, (b+e)/2, l, r);
    int rv = g(n*2 + 1, (b+e)/2 + 1, e, l, r);

    if(lv &amp;lt; 0) return rv;
    if(rv &amp;lt; 0) return lv;

    if(v[lv] &amp;lt; v[rv]) return lv;
    else return rv;
}

int f(int l, int r) {
    int idx = g(1, 1, N, l, r);
    int ret = (w[r] - w[l-1]) * v[idx];

    if(idx+1 &amp;lt;= r) ret = max(ret, f(idx+1, r));
    if(idx-1 &amp;gt;= l) ret = max(ret, f(l, idx-1));

    return ret;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    cin &amp;gt;&amp;gt; N;

    v.resize(N+1);
    w.resize(N+1);

    for(int i=1; i&amp;lt;=N; i++) {
        cin &amp;gt;&amp;gt; v[i];

        w[i] = w[i-1] + v[i];
    }

    u.resize(N*4);
    init(1, 1, N);

    cout &amp;lt;&amp;lt; f(1, N) &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 1989번 : 부분배열 고르기 2&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;세그먼트 트리&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 문제와 동일하나 이번에는 구간의 주소까지 구해주어야 하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간 복잡도를 줄여야 하거나 다른 전략을 사용해야 하는 것은 아니고, left 값과 right 값을 인자로 같이 전달해주기만 하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구조체를 사용하여 3개의 값을 한꺼번에 전달할 수 있도록 구현하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1664030300367&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

int N;
vector&amp;lt;int&amp;gt; v, u, w;

int init(int n, int b, int e) {
    if(b == e) return u[n] = b;

    int lv = init(n*2, b, (b+e)/2);
    int rv = init(n*2 + 1, (b+e)/2 + 1, e);

    if(v[lv] &amp;lt; v[rv]) return u[n] = lv;
    else return u[n] = rv;
}

int g(int n, int b, int e, int l, int r) {
    if(r &amp;lt; b || e &amp;lt; l) return -1;
    if(l &amp;lt;= b &amp;amp;&amp;amp; e &amp;lt;= r) return u[n];

    int lv = g(n*2, b, (b+e)/2, l, r);
    int rv = g(n*2 + 1, (b+e)/2 + 1, e, l, r);

    if(lv &amp;lt; 0) return rv;
    if(rv &amp;lt; 0) return lv;

    if(v[lv] &amp;lt; v[rv]) return lv;
    else return rv;
}

struct s { int l, r, a; };

s f(int l, int r) {
    int idx = g(1, 1, N, l, r);
    int area = (w[r] - w[l-1]) * v[idx];

    s ret = {l, r, area};

    if(idx+1 &amp;lt;= r) {
        s tmp = f(idx+1, r);

        if(tmp.a &amp;gt; ret.a) ret = tmp;
    }
    if(idx-1 &amp;gt;= l) {
        s tmp = f(l, idx-1);

        if(tmp.a &amp;gt; ret.a) ret = tmp;
    }

    return ret;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    cin &amp;gt;&amp;gt; N;

    v.resize(N+1);
    w.resize(N+1);

    for(int i=1; i&amp;lt;=N; i++) {
        cin &amp;gt;&amp;gt; v[i];

        w[i] = w[i-1] + v[i];
    }

    u.resize(N*4);
    init(1, 1, N);

    s ans = f(1, N);

    cout &amp;lt;&amp;lt; ans.a &amp;lt;&amp;lt; &quot;\n&quot;;
    cout &amp;lt;&amp;lt; ans.l &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; ans.r &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 11143번 : Beads&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;세그먼트 트리&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 상자가 있고, 쿼리 P에 대해서는 a번 상자에 구슬 b개를 추가하고, 쿼리 Q에 대해서는 a번 상자부터 b번 상자까지 모든 구슬의 개수의 합을 구하는 처리를 하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구간 합 구하기 문제를 활용하여 거의 비슷하게 풀이할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 초기 상자들에는 구슬이 모두 0개 들어있으므로 init 함수와 같은 것을 구현할 필요가 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;값을 갱신할 때는 특정 인덱스의 값을 바꾸는 것이 아닌 더하는 것이므로, diff = b로 설정해주고 v[a] += b와 같이 해주면 갱신이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1664038877652&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;int&amp;gt; v, u;

void upd(int n, int b, int e, int idx, int diff) {
    if(idx &amp;lt; b || e &amp;lt; idx) return;

    u[n] += diff;

    if(b &amp;lt; e) {
        upd(n*2, b, (b+e)/2, idx, diff);
        upd(n*2 + 1, (b+e)/2 + 1, e, idx, diff);
    }
}

int f(int n, int b, int e, int l, int r) {
    if(r &amp;lt; b || e &amp;lt; l) return 0;
    if(l &amp;lt;= b &amp;amp;&amp;amp; e &amp;lt;= r) return u[n];

    return f(n*2, b, (b+e)/2, l, r) + f(n*2 + 1, (b+e)/2 + 1, e, l, r);
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    while(T--) {
        int N, M, K; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M &amp;gt;&amp;gt; K;

        v.clear();
        v.resize(N+1);

        u.clear();
        u.resize(N*4);

        M += K;

        while(M--) {
            char Q; int a, b; cin &amp;gt;&amp;gt; Q &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

            if(Q == 'P') {
                int diff = b;
                v[a] += b;
                upd(1, 1, N, a, diff);
            }
            else if(Q == 'Q') cout &amp;lt;&amp;lt; f(1, 1, N, a, b) &amp;lt;&amp;lt; &quot;\n&quot;;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/백준(BOJ) 문제풀이</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/629</guid>
      <comments>https://restudycafe.tistory.com/629#entry629comment</comments>
      <pubDate>Sat, 24 Sep 2022 22:40:08 +0900</pubDate>
    </item>
    <item>
      <title>백준 BOJ 새로 나온 문제들 풀어보기 220904</title>
      <link>https://restudycafe.tistory.com/628</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 25513번 : 빠른 오름차순 숫자 탐색&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 :&lt;span style=&quot;color: #ee2323;&quot;&gt; BFS&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주어진 5 x 5 크기의 배열에서, 특정 위치에서 시작하여 1, 2, 3, 4, 5, 6을 순서대로 방문하는 최소 경로의 길이를 구하는 문제이다. (이 때, -1은 지나갈 수 없는 칸이며 만약 순서대로 방문하는 것이 불가능하다면 -1을 출력해야 한다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BFS를 반복문으로 여러 번 사용하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초기 위치에서 cur(1 ~ 6으로 반복문을 돌려준다.)를 방문하는 BFS를 구현하고, 방문이 되었다면 초기 위치를 해당 칸의 위치로 바꿔주고 다음 루프를 돌면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 방문이 불가능하다면 -1을 출력해주고 즉시 종료해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1662273567233&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; v(5, vector&amp;lt;int&amp;gt;(5));

    for(int i=0; i&amp;lt;5; i++)
        for(int j=0; j&amp;lt;5; j++) cin &amp;gt;&amp;gt; v[i][j];

    int si, sj; cin &amp;gt;&amp;gt; si &amp;gt;&amp;gt; sj;

    int ans = 0;

    for(int cur=1; cur&amp;lt;=6; cur++) {
        queue&amp;lt;pair&amp;lt;int, int&amp;gt;&amp;gt; q;
        q.push({si, sj});

        vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; dis(5, vector&amp;lt;int&amp;gt;(5, -1));
        dis[si][sj] = 0;

        bool check = false;

        while(!q.empty()) {
            int x = q.front().first;
            int y = q.front().second;
            q.pop();

            if(v[x][y] == cur) {
                ans += dis[x][y];
                si = x, sj = y;

                check = true;
                break;
            }

            int dx[4] = {1, -1, 0, 0};
            int dy[4] = {0, 0, 1, -1};

            for(int i=0; i&amp;lt;4; i++) {
                int nx = x + dx[i];
                int ny = y + dy[i];

                if(nx &amp;lt; 0 || ny &amp;lt; 0 || nx &amp;gt;= 5 || ny &amp;gt;= 5) continue;
                if(dis[nx][ny] != -1 || v[nx][ny] == -1) continue;

                dis[nx][ny] = dis[x][y] + 1;
                q.push({nx, ny});
            }
        }

        if(!check) {
            cout &amp;lt;&amp;lt; -1 &amp;lt;&amp;lt; &quot;\n&quot;;
            return 0;
        }
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 25512번 : 트리를 간단하게 색칠하는 최소 비용&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;트리, 그래프 탐색&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주어진 트리에 대해 각 노드를 검은색 또는 흰색으로 칠하는 비용이 주어지고, 인접한 노드는 다른 색으로 칠하려고 할 때 모든 노드를 칠하는 최소 비용을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리이기 때문에 사이클이 없고, 따라서 하나의 노드의 색을 결정하면 모든 나머지 노드들의 색이 결정된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 루트 노드를 검은색으로 칠하는 경우와, 흰색으로 칠하는 경우 두 가지를 구한 뒤 비교해서 최솟값을 출력해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1662272940505&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

int N;
vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; v, u;
int a = 0, b = 0;

void f(int x, int pre) {
    if(pre == 0) a += v[x];
    else a += u[x];

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        if(pre == 0) f(adj[x][i], 1);
        else f(adj[x][i], 0);
    }
}

void g(int x, int pre) {
    if(pre == 0) b += v[x];
    else b += u[x];

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        if(pre == 0) g(adj[x][i], 1);
        else g(adj[x][i], 0);
    }
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    cin &amp;gt;&amp;gt; N;

    adj.resize(N);

    for(int i=0; i&amp;lt;N-1; i++) {
        int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

        adj[a].push_back(b);
    }

    v.resize(N);
    u.resize(N);

    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i] &amp;gt;&amp;gt; u[i];

    f(0, 0);

    g(0, 1);

    cout &amp;lt;&amp;lt; min(a, b) &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 25516번 : 거리가 k이하인 트리 노드에서 사과 수확하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;트리, 그래프 탐색&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리가 주어지고, 루트 노드에서 거리가 k 이하인 노드들에서만 사과를 수확할 때 그 개수를 구하는 문제이다. (각 노드의 사과 개수가 주어진다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;깊이가 k 이하인 노드를 모두 방문하여 노드의 사과 개수를 답에 더해준 뒤, 답을 출력해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1662272849270&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

int N, M, ans = 0;
vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; v;

void f(int x, int dep) {
    ans += v[x];

    if(dep == M) return;

    for(int i=0; i&amp;lt;adj[x].size(); i++) f(adj[x][i], dep+1);
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    adj.resize(N);

    for(int i=0; i&amp;lt;N-1; i++) {
        int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

        adj[a].push_back(b);
    }

    v.resize(N);
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];

    f(0, 0);

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 25511번 : 값이 k인 트리 노드의 깊이&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;트리, 그래프 탐색&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리에서 각 노드가 가지는 값이 따로 주어질 때, 값 k를 가지는 노드의 깊이를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;루트 노드에서부터 재귀적으로 탐색하다가 노드 값이 k인 노드를 방문했을 때의 깊이를 답으로 저장해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;탐색이 끝나고 나서 답을 출력해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1662273016775&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

int N, M;
vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj;
vector&amp;lt;int&amp;gt; v;
int ans;

void f(int x, int dep) {
    if(v[x] == M) ans = dep;

    for(int i=0; i&amp;lt;adj[x].size(); i++) f(adj[x][i], dep+1);
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    adj.resize(N);

    for(int i=0; i&amp;lt;N-1; i++) {
        int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

        adj[a].push_back(b);
    }

    v.resize(N);
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];

    f(0, 0);

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 25527번 : Counting Peaks of Infection&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;구현&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 제목 그대로 그래프의 피크의 개수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;v[i] &amp;gt; v[i-1]이면서 동시에 v[i] &amp;lt; v[i+1]인 i의 개수를 세어주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1662273084736&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    while(true) {
        int N; cin &amp;gt;&amp;gt; N;
        if(N == 0) break;

        vector&amp;lt;int&amp;gt; v(N);
        for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];

        int ans = 0;

        for(int i=1; i&amp;lt;N-1; i++)
            if(v[i] &amp;gt; v[i-1] &amp;amp;&amp;amp; v[i] &amp;gt; v[i+1]) ans++;

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/알고리즘 공부 내용 정리</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/628</guid>
      <comments>https://restudycafe.tistory.com/628#entry628comment</comments>
      <pubDate>Sun, 4 Sep 2022 15:31:33 +0900</pubDate>
    </item>
    <item>
      <title>무작위화 알고리즘 문제 풀이 모음 220903</title>
      <link>https://restudycafe.tistory.com/627</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 12041번 : Password Security (Small 2)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;무작위화, 구성적&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 대문자 알파벳을 하나씩 사용하여 26자리 비밀번호를 만들 때, 해당 비밀번호가 N개의 주어진 문자열을 포함하지 않도록 만드는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1 ~ 26으로 이루어진 순열을 무작위로 만든 뒤, 이 순열에 해당하는 문자열이 N개의 문자열을 포함하지 않을 때까지 돌리면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 아예 불가능한 경우가 있는데, 이를 해결하기 위해 1만번까지는 돌려보고, 그래도 해당하는 정답이 없으면 impossible로 간주해주면 모든 테스트케이스를 통과할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(참고로 1천번은 넉넉하지 않아 WA를 받을 확률이 높다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1662223516430&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    mt19937 mt((unsigned int)time(NULL));
    uniform_int_distribution&amp;lt;int&amp;gt; uid(0, INT_MAX);
    auto rd = bind(uid, mt);

    int T; cin &amp;gt;&amp;gt; T;

    for(int t=1; t&amp;lt;=T; t++) {
        int N; cin &amp;gt;&amp;gt; N;

        vector&amp;lt;string&amp;gt; v(N);
        for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];

        bool found = false;

        for(int r=0; r&amp;lt;1e4; r++) {
            vector&amp;lt;int&amp;gt; u;
            vector&amp;lt;bool&amp;gt; w(26);

            while(u.size() &amp;lt; 26) {
                int x = rd() % 26;

                if(!w[x]) {
                    u.push_back(x);
                    w[x] = true;
                }
            }

            string str = &quot;&quot;;

            for(int i=0; i&amp;lt;u.size(); i++) str += char('A' + u[i]);

            bool check = true;

            for(int i=0; i&amp;lt;N; i++)
                if(str.find(v[i]) &amp;gt;= 0 &amp;amp;&amp;amp; str.find(v[i]) &amp;lt; str.length()) check = false;

            if(check) {
                cout &amp;lt;&amp;lt; &quot;Case #&quot; &amp;lt;&amp;lt; t &amp;lt;&amp;lt; &quot;: &quot; &amp;lt;&amp;lt; str &amp;lt;&amp;lt; &quot;\n&quot;;

                found = true;
                break;
            }
        }

        if(!found) cout &amp;lt;&amp;lt; &quot;Case #&quot; &amp;lt;&amp;lt; t &amp;lt;&amp;lt; &quot;: IMPOSSIBLE\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 코드로 &lt;b&gt;백준 BOJ 12040번 : Password Security (Small 1)&lt;/b&gt;을 풀 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 18205번 : Farming Mars&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;무작위화, 값/좌표 압축&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개 토양의 산성도가 주어지고, 사용할 수 있는 땅이란 그 구간에서 절반보다 많은 값들이 동일한 산성도를 가지는 땅이라고 할 때, M개 쿼리에 대해 [l, r] 구간을 사용할 수 있는지 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;백준 BOJ 2912번 : 백설공주와 난쟁이&lt;/b&gt;에서 풀었던 방식과 똑같이 구현했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 여기서는 소수점 아래 6자리까지 비교해야하므로, 1e6을 곱해준 뒤 좌표 압축을 해주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브루트포스로 돌아간다고 한다. (범위만 조금 더 컸어도 비슷한 문제가 있어 나름 꿀문제인데..)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1662307661579&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    mt19937 mt((unsigned int)time(NULL));
    uniform_int_distribution&amp;lt;int&amp;gt; uid(0, INT_MAX);
    auto rd = bind(uid, mt);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    vector&amp;lt;int&amp;gt; v(N), u(N);
    for(int i=0; i&amp;lt;N; i++) {
        double x; cin &amp;gt;&amp;gt; x;

        int y = x * 1e6;

        v[i] = u[i] = y;
    }

    sort(u.begin(), u.end());
    u.erase(unique(u.begin(), u.end()), u.end());

    vector&amp;lt;int&amp;gt; w(N);
    for(int i=0; i&amp;lt;v.size(); i++)
        w[i] = lower_bound(u.begin(), u.end(), v[i]) - u.begin();

    vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; vv(1e4 + 1);

    for(int i=0; i&amp;lt;N; i++) vv[w[i]].push_back(i);

    while(M--) {
        int l, r; cin &amp;gt;&amp;gt; l &amp;gt;&amp;gt; r;

        l--, r--;

        bool check = false;

        for(int i=0; i&amp;lt;100; i++) {
            int x = w[l + (rd() % (r-l+1))];

            int cnt = upper_bound(vv[x].begin(), vv[x].end(), r) - lower_bound(vv[x].begin(), vv[x].end(), l);

            if(cnt &amp;gt; (r-l+1)/2) {
                cout &amp;lt;&amp;lt; &quot;usable\n&quot;;

                check = true;
                break;
            }
        }

        if(!check) cout &amp;lt;&amp;lt; &quot;unusable\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 23271번 : Grzaed Grains&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;무작위화&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(x, y)를 중심으로 반지름 r인 원이 10개 이하로 존재할 때 이 원들의 합집합의 넓이를 구하는 문제이다. (x, y, r 모두 -10 ~ 10 사이의 정수이며, 답은 오차 범위 10% 이내이기만 하면 된다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;범위가 매우 작고, 오차 범위는 매우 크다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제에 한해서만 특이한 방법으로 풀 수가 있는데, 바로 점들을 무작위로 찍어서 포함되는 비율을 이용하여 구하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나의 경우에는 -20 ~ 20 사이의 x, y 좌표에 해당하는 실수를 만들어서 1e6번 찍어보고, 그 중 포함되는 것의 비율을 이용하여 전체 넓이에 대한 비율로 답을 구하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자세한 구현은 아래의 코드를 참고하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1662308384427&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { int x, y, r; };

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    mt19937 mt((unsigned int)time(NULL));
    uniform_int_distribution&amp;lt;int&amp;gt; uid(0, INT_MAX);
    auto rd = bind(uid, mt);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;s&amp;gt; v(N);
    for(int i=0; i&amp;lt;N; i++)
        cin &amp;gt;&amp;gt; v[i].x &amp;gt;&amp;gt; v[i].y &amp;gt;&amp;gt; v[i].r;

    int cnt = 0;

    for(int att=1; att&amp;lt;=1e6; att++) {
        bool check = false;

        double x = ((rd() % (int)1e5) / 1e5) * 40 - 20;
        double y = ((rd() % (int)1e5) / 1e5) * 40 - 20;

        for(int i=0; i&amp;lt;N; i++)
            if(pow(x - v[i].x, 2) + pow(y - v[i].y, 2) &amp;lt;= pow(v[i].r, 2)) check = true;

        if(check) cnt++;
    }

    double ans = pow(40, 2) * (cnt / 1e6);

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 21960번 : Consul&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;무작위화, 애드 혹 (+ 함수 구현)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N명의 선거인단이 10억명 이하의 후보 중 하나를 뽑았다고 할 때, 쿼리를 50회 이하로 사용하여 N/3보다 큰 인원에게 선발된 후보가 있는지 찾는 문제이다. (있으면 번호를 구하고, 없으면 -1을 제출)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용할 수 있는 쿼리로는 다음의 것이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kth(int i) : i번째 후보가 뽑은 후보의 번호를 리턴&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cnt(int x) : x번 후보가 뽑힌 횟수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;say_answer(int a) : 답을 a로 제출&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 N/3회 이상 뽑힌 사람이 있다면, 랜덤으로 아무 유권자나 뽑아서 그 사람이 뽑은 번호가 N/3회 이상 나왔는지 확인해보면 되고, 한 번 검사마다 1/3의 확률로 답이 나온다. (이 때 쿼리는 cnt(kth(x))로 하면 되고, 이 때 쿼리는 2회 사용된다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 이러한 수행을 최대한으로, 예를 들어 10번 해준다고 치면 답이 얻어질 확률은 1 - (2/3)^10으로 거의 무조건 답을 얻을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 최대 쿼리 개수만 찾아주면 되는데, 1번 서브테스크에서 Q &amp;le; 50 이하여야 만점이라고 하였으므로, 대략 24회 정도 cnt(kth(x))을 사용해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1662306630202&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#include &quot;grader.h&quot;
using namespace std;

int kth(int k);
void say_answer(int k);
int cnt(int k);

void solve(int n)
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    mt19937 mt((unsigned int)time(NULL));
    uniform_int_distribution&amp;lt;int&amp;gt; uid(0, 1e5);
    auto rd = bind(uid, mt);
    
    bool check = false;

    for(int i=0; i&amp;lt;24; i++) {
        int x = rd() % n + 1;
        
        if(cnt(kth(x)) &amp;gt; n/3) {
            say_answer(kth(x));
            
            check = true;
            break;
        }
    }
    
    if(!check) say_answer(-1);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 15860번 : Ninety-nine&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;게임 이론, 인터랙티브&lt;/span&gt; (+ 무작위화)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;0에서부터 시작하여 프로그램과 번갈아가며 1 또는 2를 더해서 99를 먼저 완성하는 인터랙티브 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래라면 3의 배수만 불러주면 되는데, 내가 먼저 시작하는 입장이기 때문에 최소한 한 번은 뒤집어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기 때문에 일단은 무작위로 1 또는 2를 더해서 출력하다가, 3의 배수를 취할 수 있으면 바로 취해주는 방식을 택한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1662224197442&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    mt19937 mt((unsigned int)time(NULL));
    uniform_int_distribution&amp;lt;int&amp;gt; uid(0, INT_MAX);
    auto rd = bind(uid, mt);

    int x = 0;

    while(true) {
        if(x % 3 == 0) x += (rd() % 2 + 1);
        else if(x % 3 == 1) x += 2;
        else if(x % 3 == 2) x += 1;

        cout &amp;lt;&amp;lt; x &amp;lt;&amp;lt; endl;

        if(x &amp;gt;= 99) break;

        cin &amp;gt;&amp;gt; x;

        if(x &amp;gt;= 99) break;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 16972번 : 814 - 1&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;무작위화&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2차원 좌표 평면 상의 814개의 점들을 두 점의 거리가 같은 쌍이 존재하지 않도록 출력하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 모든 점들의 좌표는 -8140 ~ 8140 사이의 정수여야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;mt19937을 이용하여 랜덤으로 814개의 점들을 출력해주면 대부분 맞는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1662222760928&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    mt19937 mt((unsigned int)time(NULL));
    uniform_int_distribution&amp;lt;int&amp;gt; uid(0, INT_MAX);
    auto rd = bind(uid, mt);

    for(int i=0; i&amp;lt;814; i++)
        cout &amp;lt;&amp;lt; (rd() % 16280) - 8140 &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; (rd() % 16280) - 8140 &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 20067번 : Nowruz 1&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;무작위화, 구성적&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 무작위화를 이용해서 풀려다가 실패해서 아래에 배치한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N x M 크기의 배열이 주어지고, 점이 있는 위치에 X들을 적절히 배치해서 모든 점들 사이의 경로가 유일하며, 막다른 길(점 주위의 3칸이 # 또는 X로 둘러싸임)이 K개 만들어지도록 하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1 ~ 10까지 문제가 있는데 1번 문제의 경우에는 범위가 작아서 노가다로 풀 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1662228794249&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;X.X.#.X.X.X#.X#X
..#.............
X...X.X.X.X#.X.X
..XX.X##.XX.X..#
X##..........X..
....XX.XX.#.X..X
X.X##...X..X..#X
...X.X.XXX..X...
X.X.....X..X.X.X
...X.#.X.X...X..
X.X.XX....#X.X.X
....X..X.XX..X.X
#.X.XX.X#XXX.X..
...XX.X.X.X.XX.X
X#..............
XX.X.X.X.X.X.XXX&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/알고리즘 공부 내용 정리</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/627</guid>
      <comments>https://restudycafe.tistory.com/627#entry627comment</comments>
      <pubDate>Sun, 4 Sep 2022 02:55:43 +0900</pubDate>
    </item>
    <item>
      <title>Mo's 알고리즘 (모스 알고리즘) 구현해보기 220902</title>
      <link>https://restudycafe.tistory.com/626</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Mo's 알고리즘&lt;/b&gt;이란 &lt;span style=&quot;color: #ee2323;&quot;&gt;오프라인 쿼리&lt;/span&gt;(= &lt;u&gt;원소의 업데이트가 없어야 함&lt;/u&gt;)를 특정한 순서로 배치하여 효율적으로 처리하는 알고리즘이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 제곱근 분할법(= 루트 N개의 버킷으로 나누어, 원소들을 버킷 단위로 다루다가 필요할 때 원소 단위로 들어가 값을 다룸)을 활용하여 하나의 쿼리를 O(&amp;radic;N) 시간에 처리할 수 있다는 점에서 특이한 시간 복잡도를 갖는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;** kks227님의 블로그를 통해 공부하였다. 문제도 거기서 소개한 문제들을 공부했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 11659번 : 구간 합 구하기 (연습용)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;누적 합&lt;/span&gt; (..이지만? &lt;span style=&quot;color: #ee2323;&quot;&gt;Mo's&lt;/span&gt; 알고리즘으로 풀어보았다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;굳이 Mo's 알고리즘까지 필요하지는 않지만, 쿼리들을 재배치하여 풀어볼 수 있는 문제라는 점에서 한 번쯤 이런 방식으로 풀어보는 것도 나쁘지 않은 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿼리들의 구간 left, right 값에 따라 sqrt(N) 크기로 쪼개어 정렬하였으므로, 최악의 경우에도 각 쿼리마다 왼쪽 끝을 조정하는데에는 &lt;span&gt;&amp;radic;N번을 넘어가지 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그리고 오른쪽 끝은 모든 쿼리를 통틀어 N번 이상 이동이 발생하지 않으므로, 둘을 종합해보면 O(M&amp;radic;N + N)이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1662041961978&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

int S;
struct query { int l, r, n; };

bool cmp(query a, query b) {
    if(a.l / S != b.l / S) return a.l / S &amp;lt; b.l / S;
    else return a.r &amp;lt; b.r;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    vector&amp;lt;int&amp;gt; v(N);
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];

    S = sqrt(N);

    vector&amp;lt;query&amp;gt; Q(M);

    for(int i=0; i&amp;lt;M; i++) {
        int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

        Q[i].l = a - 1, Q[i].r = b - 1, Q[i].n = i;
    }

    sort(Q.begin(), Q.end(), cmp);

    vector&amp;lt;int&amp;gt; ans(M);
    int tmp = 0, l = Q[0].l, r = Q[0].r;

    for(int i=l; i&amp;lt;=r; i++) tmp += v[i];
    ans[Q[0].n] = tmp;

    for(int i=1; i&amp;lt;M; i++) {
        while(Q[i].l &amp;lt; l) tmp += v[--l];
        while(Q[i].r &amp;gt; r) tmp += v[++r];

        while(Q[i].l &amp;gt; l) tmp -= v[l++];
        while(Q[i].r &amp;lt; r) tmp -= v[r--];

        ans[Q[i].n] = tmp;
    }

    for(int i=0; i&amp;lt;M; i++) cout &amp;lt;&amp;lt; ans[i] &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 13547번 : 수열과 쿼리 5&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;오프라인 쿼리, Mo's&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;676&quot; data-origin-height=&quot;395&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVsWy7/btrLcI0ltQd/GdJA2MitSEa2ke64jtxewk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVsWy7/btrLcI0ltQd/GdJA2MitSEa2ke64jtxewk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVsWy7/btrLcI0ltQd/GdJA2MitSEa2ke64jtxewk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVsWy7%2FbtrLcI0ltQd%2FGdJA2MitSEa2ke64jtxewk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;676&quot; height=&quot;395&quot; data-origin-width=&quot;676&quot; data-origin-height=&quot;395&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿼리 a b에 대해 a ~ b 구간 사이의 서로 다른 수의 개수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역시 마찬가지로 쿼리를 left / S 값의 오름차순, 그리고 left / S가 동률일 경우 right 값을 오름차순으로 정렬해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 쿼리에 대해서는 개수를 일일이 세어서 구해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 각 쿼리들에 대해서 정렬된 순서대로 구간을 변경하며 각 수들을 count 해주면서 답을 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수를 증가시켰는데 원래 0이었으면 수의 종류가 하나 늘어난 것이고, 수를 감소시켰는데 0이 된다면 수의 종류가 하나 감소한 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1662211258172&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

int S;
struct query { int l, r, n; };

bool cmp(query a, query b) {
    if(a.l / S != b.l / S) return a.l / S &amp;lt; b.l / S;
    else return a.r &amp;lt; b.r;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;int&amp;gt; v(N);
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];

    S = sqrt(N);

    int M; cin &amp;gt;&amp;gt; M;

    vector&amp;lt;query&amp;gt; Q(M);

    for(int i=0; i&amp;lt;M; i++) {
        int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

        Q[i].l = a - 1, Q[i].r = b - 1, Q[i].n = i;
    }

    sort(Q.begin(), Q.end(), cmp);

    vector&amp;lt;int&amp;gt; ans(M), cnt(1e6 + 1);
    int val = 0, l = Q[0].l, r = Q[0].r;

    for(int i=l; i&amp;lt;=r; i++) {
        if(cnt[v[i]] == 0) val++;
        cnt[v[i]]++;
    }

    ans[Q[0].n] = val;

    for(int i=1; i&amp;lt;M; i++) {
        while(Q[i].l &amp;lt; l)
            if(cnt[v[--l]]++ == 0) val++;

        while(Q[i].r &amp;gt; r)
            if(cnt[v[++r]]++ == 0) val++;

        while(Q[i].l &amp;gt; l)
            if(--cnt[v[l++]] == 0) val--;

        while(Q[i].r &amp;lt; r)
            if(--cnt[v[r--]] == 0) val--;

        ans[Q[i].n] = val;
    }

    for(int i=0; i&amp;lt;M; i++) cout &amp;lt;&amp;lt; ans[i] &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 2912번 : 백설공주와 난쟁이&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt; Platinum II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;무작위화, 오프라인 쿼리, Mo's&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 (10,000 이하의) 수가 주어지고, K개의 쿼리 a b에 대해 a ~ b 구간에서 절반보다 많이 나타나는 수가 있는지 확인하고 그러한 수가 있다면 그것을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 Mo's로 먼저 접근해보려 했는데 구간에 따라 과반수 이상인 수가 바뀌면 갱신을 어떻게 해야할지 모르겠어서 일단 다른 방법으로 푸는 방식을 참고했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방법은 이러한데, 먼저 주어진 구간에서 하나의 수를 랜덤으로 고른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 그 수가 구간에서 절반 이상 나왔는지 체크하여 그렇다면 바로 출력해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최악의 경우 어떤 수가 절반에 아주 가까운 과반수라고 하더라도 랜덤으로 뽑았을 때 그 수가 나타날 확률은 1/2보다 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 과반수 이상 존재하는 수가 있음에도 100번 뽑아서 그 수가 나타나지 않을 확률은 (1/2)^100보다 작다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 어떤 수가 구간에서 절반 이상 나왔는지 빠르게 체크하는 방법인데, 이것은 처음에 배열을 입력받을 때 2차원 벡터에서 해당 수의 주소에 그 수의 주소를 push_back 해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 나중에 어떤 수 x가 l ~ r 구간에서 몇 번 나왔는지 체크할 때, upper_bound(u[x].begin(), u[x].end(), r) - lower_bound(u[x].begin(), u[x].end(), l); 의 방식으로 O(log M) 시간에 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;난수 생성은 mt19937, 메르센 트위스터라는 난수 생성기를 이용하여 구현해보았다. (처음 써본다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1662214056752&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    mt19937 mt((unsigned int)time(NULL));
    uniform_int_distribution&amp;lt;int&amp;gt; uid(0, INT_MAX);
    auto rd = bind(uid, mt);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    vector&amp;lt;int&amp;gt; v(N+1);
    vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; u(M+1);

    for(int i=1; i&amp;lt;=N; i++) {
        cin &amp;gt;&amp;gt; v[i];

        u[v[i]].push_back(i);
    }

    int K; cin &amp;gt;&amp;gt; K;

    while(K--) {
        int l, r; cin &amp;gt;&amp;gt; l &amp;gt;&amp;gt; r;

        bool check = false;

        for(int i=0; i&amp;lt;100; i++) {
            int x = v[l + (rd() % (r-l+1))];

            int cnt = upper_bound(u[x].begin(), u[x].end(), r) - lower_bound(u[x].begin(), u[x].end(), l);

            if(cnt &amp;gt; (r-l+1)/2) {
                cout &amp;lt;&amp;lt; &quot;yes &quot; &amp;lt;&amp;lt; x &amp;lt;&amp;lt; &quot;\n&quot;;

                check = true;
                break;
            }
        }

        if(!check) cout &amp;lt;&amp;lt; &quot;no\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/알고리즘 공부 내용 정리</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/626</guid>
      <comments>https://restudycafe.tistory.com/626#entry626comment</comments>
      <pubDate>Thu, 1 Sep 2022 23:30:05 +0900</pubDate>
    </item>
    <item>
      <title>백준 BOJ 문제 풀이 기록 220831</title>
      <link>https://restudycafe.tistory.com/625</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 18017번 : 총알의 속도&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;b&gt;난이도를 매길 수 없음&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;물리학&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A m/s로 달리며 B m/s로 총알을 발사했을 때 총알의 속력을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 A, B는 10^8 이하이며, 10^(-9) 이내의 오차로 답을 구해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상대성 이론을 사용하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐하면 속력이 10^8 수준까지 매우 커지면 빛의 속력을 고려할 필요가 있기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 다음의 공식을 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;260&quot; data-origin-height=&quot;135&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NXu91/btrLhuIXR0W/XcUx6AU02DGgj1eyXnIuc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NXu91/btrLhuIXR0W/XcUx6AU02DGgj1eyXnIuc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NXu91/btrLhuIXR0W/XcUx6AU02DGgj1eyXnIuc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNXu91%2FbtrLhuIXR0W%2FXcUx6AU02DGgj1eyXnIuc0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;260&quot; height=&quot;135&quot; data-origin-width=&quot;260&quot; data-origin-height=&quot;135&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1662178292013&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    double a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

    double c = 299792458;

    double ans = (a + b) / (1 + (a * b) / (c * c));

    cout &amp;lt;&amp;lt; fixed;
    cout.precision(9);

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 3154번 : 알람시계&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간을 맞출 때 시는 24로 나눈 나머지로, 분은 60으로 나눈 나머지로 자동으로 맞춰진다고 할 때 번호키 사이의 맨해튼 거리의 합이 가장 작도록 시간을 입력하려면 어떻게 입력해야 하는지 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;번호키가 수식 하나로 거리를 나타내기 어려우므로, 일단은 번호와 번호 사이의 거리를 모두 구해주고 00:00부터 99:99까지 중에 조건에 해당하면서 가장 거리의 합이 작은 것을 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661917563586&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int a, b; scanf(&quot;%02d:%02d&quot;, &amp;amp;a, &amp;amp;b);

    int v[10][10] = {{0, 4, 3, 4, 3, 2, 3, 2, 1, 2},
                     {4, 0, 1, 2, 1, 2, 3, 2, 3, 4},
                     {3, 1, 0, 1, 2, 1, 2, 3, 2, 3},
                     {4, 2, 1, 0, 3, 2, 1, 4, 3, 2},
                     {3, 1, 2, 3, 0, 1, 2, 1, 2, 3},
                     {2, 2, 1, 2, 1, 0, 1, 2, 1, 2},
                     {3, 3, 2, 1, 2, 1, 0, 3, 2, 1},
                     {2, 2, 3, 4, 1, 2, 3, 0, 1, 2},
                     {1, 3, 2, 3, 2, 1, 2, 1, 0, 1},
                     {2, 4, 3, 2, 3, 2, 1, 2, 1, 0}};

    int Min = INT_MAX, x, y;

    for(int i=0; i&amp;lt;100; i++)
        for(int j=0; j&amp;lt;100; j++) {
            if(i % 24 != a || j % 60 != b) continue;

            int sum = v[i/10][i%10] + v[i%10][j/10] + v[j/10][j%10];

            if(sum &amp;lt; Min) {
                Min = sum;
                x = i, y = j;
            }
        }

    printf(&quot;%02d:%02d\n&quot;, x, y);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 5371번 : Annoying Mosquitos&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 모기의 좌표가 주어지고, M개의 파리채의 중심 좌표가 주어질 때, 파리채는 중심 좌표를 기준으로 가로 세로 &amp;plusmn;50만큼의 범위에 있는 모기를 잡을 수 있다고 한다면 잡을 수 있는 모기의 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브루트포스로 각 파리채의 위치에 대해 잡히는 모기들을 bool 변수로 check 해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 파리채 검사 이후 최종적으로 check 되어있는 모기들의 수를 구하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661932149194&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    while(T--) {
        int N; cin &amp;gt;&amp;gt; N;

        vector&amp;lt;pair&amp;lt;int, int&amp;gt;&amp;gt; v(N);
        for(int i=0; i&amp;lt;N; i++)
            cin &amp;gt;&amp;gt; v[i].first &amp;gt;&amp;gt; v[i].second;

        vector&amp;lt;bool&amp;gt; u(N);

        int M; cin &amp;gt;&amp;gt; M;

        while(M--) {
            int x, y; cin &amp;gt;&amp;gt; x &amp;gt;&amp;gt; y;

            for(int i=0; i&amp;lt;N; i++) {
                if(v[i].first &amp;lt;= x + 50 &amp;amp;&amp;amp; v[i].first &amp;gt;= x - 50
                   &amp;amp;&amp;amp; v[i].second &amp;lt;= y + 50 &amp;amp;&amp;amp; v[i].second &amp;gt;= y - 50) u[i] = true;
            }
        }

        int ans = 0;

        for(int i=0; i&amp;lt;N; i++)
            if(u[i]) ans++;

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 5768번 : Divide and Conquer&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주어진 a ~ b 사이의 수 중에서 약수의 개수가 가장 많은 것, 그리고 그러한 수가 여러 개라면 가장 큰 수를 구하고, 그 약수의 개수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직접 a ~ b 사이의 모든 수들에 대해 약수의 개수를 구해보면서 그들 중 가장 큰 수를 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661932937034&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    while(true) {
        int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;
        if(a == 0 &amp;amp;&amp;amp; b == 0) break;

        int Max = 0, ans;

        for(int i=a; i&amp;lt;=b; i++) {
            int cnt = 0;

            for(int j=1; j&amp;lt;=i; j++) {
                if(i % j == 0) cnt++;
            }

            if(cnt &amp;gt;= Max) {
                Max = cnt;
                ans = i;
            }
        }

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; Max &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 6367번 : Color Me Less&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;16개의 값들 중 RGB 거리가 가장 가까운 것을 매칭시켜주는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매 테스트케이스마다 16개의 값들에 대한 거리를 직접 구한 뒤 그들 중 가장 작은 것을 직접 찾아주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특별히 다른 처리를 하지 않았는데 맞는 것을 보면 RGB 거리가 같은 두 점이 존재하지는 않는 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1662179220503&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { int a, b, c; };

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    vector&amp;lt;s&amp;gt; v(16);
    for(int i=0; i&amp;lt;16; i++)
        cin &amp;gt;&amp;gt; v[i].a &amp;gt;&amp;gt; v[i].b &amp;gt;&amp;gt; v[i].c;

    while(true) {
        int a, b, c; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b &amp;gt;&amp;gt; c;
        if(a == -1 &amp;amp;&amp;amp; b == -1 &amp;amp;&amp;amp; c == -1) break;

        int Min = INT_MAX, x, y, z;

        for(int i=0; i&amp;lt;16; i++) {
            int val = pow(a - v[i].a, 2) + pow(b - v[i].b, 2) + pow(c - v[i].c, 2);

            if(val &amp;lt; Min) {
                Min = val;
                x = v[i].a, y = v[i].b, z = v[i].c;
            }
        }

        cout &amp;lt;&amp;lt; &quot;(&quot; &amp;lt;&amp;lt; a &amp;lt;&amp;lt; &quot;,&quot; &amp;lt;&amp;lt; b &amp;lt;&amp;lt; &quot;,&quot; &amp;lt;&amp;lt; c &amp;lt;&amp;lt; &quot;) maps to (&quot;
              &amp;lt;&amp;lt; x &amp;lt;&amp;lt; &quot;,&quot; &amp;lt;&amp;lt; y &amp;lt;&amp;lt; &quot;,&quot; &amp;lt;&amp;lt; z &amp;lt;&amp;lt; &quot;)\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 11321번 : Addition Affliction&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 수를 더한 일의 자리가 0이 되는 조합을 먼저 계산하도록 수식의 앞에 배치해주는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞에서부터 2중 for문을 돌리며 두 수의 합이 10으로 나누어떨어지는 것들을 체크해서 벡터에 push back 해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 체크가 된 것은 건너뛰어주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1662179318918&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    while(true) {
        string str; cin &amp;gt;&amp;gt; str;
        if(str == &quot;0&quot;) break;

        vector&amp;lt;int&amp;gt; v;
        string tmp = &quot;&quot;;

        for(int i=0; i&amp;lt;str.length(); i++) {
            if(str[i] != '+') tmp += str[i];
            else {
                v.push_back(stoi(tmp));
                tmp = &quot;&quot;;
            }
        }
        v.push_back(stoi(tmp));
        tmp = &quot;&quot;;

        vector&amp;lt;bool&amp;gt; u(v.size());
        bool fir = true;

        for(int i=0; i&amp;lt;v.size(); i++) {
            if(u[i]) continue;

            int idx = -1;

            for(int j=i+1; j&amp;lt;v.size(); j++) {
                if((v[i] + v[j]) % 10 == 0 &amp;amp;&amp;amp; !u[j]) idx = j;
            }

            if(idx != -1) {
                if(fir) fir = false;
                else cout &amp;lt;&amp;lt; &quot;+&quot;;

                cout &amp;lt;&amp;lt; v[i] &amp;lt;&amp;lt; &quot;+&quot; &amp;lt;&amp;lt; v[idx];
                u[i] = u[idx] = true;
            }
        }

        for(int i=0; i&amp;lt;u.size(); i++)
            if(!u[i]) {
                if(fir) fir = false;
                else cout &amp;lt;&amp;lt; &quot;+&quot;;

                cout &amp;lt;&amp;lt; v[i];
            }

        cout &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 11504번 : 돌려 돌려 돌림판&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;돌림판의 한 칸에 숫자가 한 개씩 적혀있고, 그 중 한 칸을 골라 시계방향으로 선택한 수들을 이어붙인 수가 두 수 사이의 값이 되는 경우를 모두 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제에서 말한 경우를 모두 세어주기만 하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떻게 보면 구현 문제에 가깝다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1662179454451&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    while(T--) {
        int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

        string a = &quot;&quot;, b = &quot;&quot;;

        for(int i=0; i&amp;lt;M; i++) {
            char c; cin &amp;gt;&amp;gt; c;

            a += c;
        }

        for(int i=0; i&amp;lt;M; i++) {
            char c; cin &amp;gt;&amp;gt; c;

            b += c;
        }

        vector&amp;lt;char&amp;gt; v(N);
        for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];

        int ans = 0;

        for(int i=0; i&amp;lt;N; i++) {
            string tmp = &quot;&quot;;

            for(int j=0; j&amp;lt;M; j++) tmp += v[(i+j) % N];

            if(tmp &amp;gt;= a &amp;amp;&amp;amp; tmp &amp;lt;= b) ans++;
        }

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 11453번 : Rummikub&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;루미큐브 조각들이 주어질 때, 색이 같고 연속한 3개의 숫자가 있거나, 숫자가 같고 색이 모두 다른 3개의 타일이 존재하는지 찾아주는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2차원 배열을 만들어서 주어진 조각들을 모두 체크해주고, 숫자와 색들을 체크해보면서 조건을 만족하는 세트가 있는지 찾아주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1662179541321&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    while(T--) {
        int N; cin &amp;gt;&amp;gt; N;

        bool v[101][4] = {};

        while(N--) {
            string str; cin &amp;gt;&amp;gt; str;

            int x = stoi(str.substr(0, str.length()-1));
            char y = str.back();

            if(y == 'b') v[x][0] = true;
            else if(y == 'g') v[x][1] = true;
            else if(y == 'r') v[x][2] = true;
            else if(y == 'y') v[x][3] = true;
        }

        bool check = false;

        for(int i=0; i&amp;lt;4; i++)
            for(int j=3; j&amp;lt;=100; j++)
                if(v[j-2][i] &amp;amp;&amp;amp; v[j-1][i] &amp;amp;&amp;amp; v[j][i]) check = true;

        for(int i=1; i&amp;lt;=100; i++) {
            int cnt = 0;

            for(int j=0; j&amp;lt;4; j++)
                if(v[i][j]) cnt++;

            if(cnt &amp;gt;= 3) check = true;
        }

        if(check) cout &amp;lt;&amp;lt; &quot;YES\n&quot;;
        else cout &amp;lt;&amp;lt; &quot;NO\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 13450번 : L&amp;aacute;szl&amp;oacute; Babai&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3개의 노드로 이루어진 2개의 그래프가 주어질 때, 이 두 개의 그래프가 isomorphism (동형) 관계인지를 파악하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노드가 3개밖에 없으므로, 간선의 수가 같으면 동일한 그래프가 될 수 밖에 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1662179605754&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    int a, b;

    while(T--) {
        int N; cin &amp;gt;&amp;gt; N;

        for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

        int M; cin &amp;gt;&amp;gt; M;

        for(int i=0; i&amp;lt;M; i++) cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

        if(N == M) cout &amp;lt;&amp;lt; &quot;yes\n&quot;;
        else cout &amp;lt;&amp;lt; &quot;no\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 13641번 : Grid de Largada&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제를 정확히는 이해 못했는데 주어진 두 개의 순열에 대해 한 순열을 최소 swap수로 swap하여 두 번째 순열을 만들기 위한 최소 횟수를 구하는 문제 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 번째 순열을 1 2 3 .. N으로 만들어주고 번호를 매칭하여 두 번째 순열도 바꿔준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 버블 정렬을 하면서 swap 횟수를 count 해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1662179714652&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N;

    while(cin &amp;gt;&amp;gt; N) {
        vector&amp;lt;int&amp;gt; v(N+1);

        for(int i=1; i&amp;lt;=N; i++) {
            int x; cin &amp;gt;&amp;gt; x;

            v[x] = i;
        }

        vector&amp;lt;int&amp;gt; u(N+1);

        for(int i=1; i&amp;lt;=N; i++) {
            int x; cin &amp;gt;&amp;gt; x;

            u[i] = v[x];
        }

        int ans = 0;

        for(int i=1; i&amp;lt;N; i++)
            for(int j=N; j&amp;gt;i; j--)
                if(u[j-1] &amp;gt; u[j]) {
                    swap(u[j-1], u[j]);

                    ans++;
                }

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 18067번 : Accurate Movement&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주어진 규칙에 따라 두 블럭을 이동시켜서, 왼쪽 끝에 붙어있는 두 블럭을 모두 오른쪽 끝으로 붙이는데 필요한 최소 이동 수를 구하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리디하게 접근하여 각 블럭을 이동할 수 있는 최대한 이동시키고, 오른쪽 끝 범위 이상으로 이동되면 그 때의 횟수를 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1662179967753&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int a, b, N; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b &amp;gt;&amp;gt; N;

    int x = a, y = b, ans = 0;

    while(true) {
        x = y;
        ans++;

        if(x &amp;gt;= N) break;

        y += b - a;
        ans++;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 18512번 : 점프 점프&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;b&gt;&lt;span style=&quot;color: #953b34;&quot;&gt; Bronze I&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 명은 지점 a에서 출발하여 한 번에 x미터씩 이동하고, 나머지 한 명은 지점 b에서 출발하여 한 번에 y미터씩 이동할 때, 두 명이 같은 지점을 지나는 가장 작은 위치를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;범위가 작아 브루트포스로 일일이 돌려보면서 확인이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1662180366266&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int a, b, x, y; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b &amp;gt;&amp;gt; x &amp;gt;&amp;gt; y;

    for(int i=0; i&amp;lt;1e5; i++) {
        if(x == y) {
            cout &amp;lt;&amp;lt; x &amp;lt;&amp;lt; &quot;\n&quot;;
            return 0;
        }

        if(x &amp;lt; y) x += a;
        else if(x &amp;gt; y) y += b;
    }

    cout &amp;lt;&amp;lt; -1 &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 20240번 : Integer Square&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;b&gt;&lt;span style=&quot;color: #953b34;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Bronze I&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 변의 길이의 제곱이 x인 정사각형의 네 정수 좌표를 아무거나 구하면 되는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원점을 기준으로 다른 지점까지의 거리의 제곱이 x인 지점을 찾아서, 90도씩 돌려서 나머지 점들을 찍어주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1662180422167&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    int a = -1, b = -1;
    bool check = false;

    for(int i=0; i&amp;lt;=1000; i++) {
        for(int j=0; j&amp;lt;=1000; j++)
            if(i*i + j*j == N) {
                a = i, b = j;
                check = true;
                break;
            }
        if(check) break;
    }

    if(a == -1 &amp;amp;&amp;amp; b == -1) {
        cout &amp;lt;&amp;lt; &quot;Impossible\n&quot;;
        return 0;
    }

    cout &amp;lt;&amp;lt; 0 &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; 0 &amp;lt;&amp;lt; &quot;\n&quot;;
    cout &amp;lt;&amp;lt; a &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; b &amp;lt;&amp;lt; &quot;\n&quot;;
    cout &amp;lt;&amp;lt; -b &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; a &amp;lt;&amp;lt; &quot;\n&quot;;
    cout &amp;lt;&amp;lt; -b + a &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; a + b &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/알고리즘 공부 내용 정리</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/625</guid>
      <comments>https://restudycafe.tistory.com/625#entry625comment</comments>
      <pubDate>Wed, 31 Aug 2022 12:46:50 +0900</pubDate>
    </item>
    <item>
      <title>백준 BOJ 브론즈 브루트포스 문제들 밀기 220830</title>
      <link>https://restudycafe.tistory.com/624</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 백준 브론즈 브루트포스 알고리즘 문제들을 밀어볼 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 3,000문제를 넘게 풀면 나머지 브론즈 문제들은 솔직히 문제를 풀기보다 번역기에 돌린 문제의 지문을 &quot;해석&quot;하는 과정이 더 어렵다. (말 그대로 문장 구조의 앞뒤가 안 맞아서 대충 그동안 푼 문제들의 경험으로 문제의 지시를 끼워맞춰야 한다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 9703번 : Anti-Arithmetic Permutation&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 수가 주어졌을 때, 순서를 뒤집지 않고 어떤 3개의 수를 선택해도 그 세 수가 등차수열을 이루지 않도록 하는 수열을 Anti-Arithmetic Permutation이라고 할 때, 주어진 수열이 Anti-Arithmetic Permutation인지를 판별하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브루트포스로 O(N^3) 시간에 3개의 수를 모두 확인해서 등차수열을 이루는 것이 하나라도 있는지 체크해보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661827965900&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    for(int t=1; t&amp;lt;=T; t++) {
        int N; cin &amp;gt;&amp;gt; N;

        vector&amp;lt;int&amp;gt; v(N);
        for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];

        bool check = true;

        for(int i=0; i&amp;lt;N; i++)
            for(int j=i+1; j&amp;lt;N; j++)
                for(int k=j+1; k&amp;lt;N; k++)
                    if(v[i] + v[k] == v[j] * 2) check = false;

        cout &amp;lt;&amp;lt; &quot;Case #&quot; &amp;lt;&amp;lt; t &amp;lt;&amp;lt; &quot;: &quot;;

        if(check) cout &amp;lt;&amp;lt; &quot;YES\n&quot;;
        else cout &amp;lt;&amp;lt; &quot;NO\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 9850번 : Cipher&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스, 문자열&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자열이 주어질 때, 이것을 shift 시킨 문자열 중 CHIPMUNKS와 LIVE가 둘 다 나오는 것을 출력하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;26개의 shift를 모두 적용해보고 그들 중 CHIPMUNKS와 LIVE가 모두 나오는지 체크해보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 단어 뒤에 .이나 !와 같은 기호가 나올 수 있기 때문에 알파벳이 아닌 경우 단어를 끊어서 검사해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661829262900&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    string str; getline(cin, str);

    for(int i=0; i&amp;lt;26; i++) {
        string tmp = &quot;&quot;;

        for(int j=0; j&amp;lt;str.length(); j++) {
            if(str[j] &amp;gt;= 'A' &amp;amp;&amp;amp; str[j] &amp;lt;= 'Z')
                tmp += 'A' + (str[j] - 'A' + i) % 26;
            else tmp += str[j];
        }

        string word = &quot;&quot;;
        bool b1 = false, b2 = false;

        for(int j=0; j&amp;lt;tmp.length(); j++) {
            if(!(tmp[j] &amp;gt;= 'A' &amp;amp;&amp;amp; tmp[j] &amp;lt;= 'Z')) {
                if(word == &quot;CHIPMUNKS&quot;) b1 = true;
                else if(word == &quot;LIVE&quot;) b2 = true;

                word = &quot;&quot;;
            }
            else word += tmp[j];
        }
        if(word == &quot;CHIPMUNKS&quot;) b1 = true;
        else if(word == &quot;LIVE&quot;) b2 = true;

        if(b1 &amp;amp;&amp;amp; b2) {
            cout &amp;lt;&amp;lt; tmp &amp;lt;&amp;lt; &quot;\n&quot;;
            break;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 9891번 : Rect&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 직사각형이 주어질 때, 두 직사각형 중 어떤 것도 서로 포함되지 않는 쌍의 개수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 가로 또는 세로 길이를 구하고, 두 길이를 길이순으로 정렬한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 (가로, 세로) 값이 각각 (a, b), (c, d)인 두 직사각형이 있다고 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 a &amp;lt; c이고 b &amp;gt; d이거나, a &amp;gt; c이고 b &amp;lt; d이면 두 직사각형은 서로 포함될 수 없게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 비교를 O(N^2) 시간에 브루트포스로 해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661830577633&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;pair&amp;lt;int, int&amp;gt;&amp;gt; v(N);

    for(int i=0; i&amp;lt;N; i++) {
        int a, b, c, d; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b &amp;gt;&amp;gt; c &amp;gt;&amp;gt; d;

        v[i] = {abs(a - c), abs(b - d)};

        if(v[i].first &amp;gt; v[i].second) swap(v[i].first, v[i].second);
    }

    int ans = 0;

    for(int i=0; i&amp;lt;N; i++)
        for(int j=i+1; j&amp;lt;N; j++)
            if((v[i].first &amp;lt; v[j].first &amp;amp;&amp;amp; v[i].second &amp;gt; v[j].second)
               || (v[i].first &amp;gt; v[j].first &amp;amp;&amp;amp; v[i].second &amp;lt; v[j].second)) ans++;

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 14290번 : Diwali lightings (Small)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무한 반복되는 문자열 패턴이 주어지고 두 수 a와 b가 주어질 때 a번째부터 b번째 문자 중에 'B'가 몇 개 등장하는지 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자열을 직접 반복해서 붙이면서 (길이가 b 이상이 될 때까지) 주어진 범위에 대해 직접 세어보면 된다. (범위가 작아서 가능하다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661831103678&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    for(int t=1; t&amp;lt;=T; t++) {
        string str; cin &amp;gt;&amp;gt; str;

        string tmp = &quot;&quot;;

        int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

        while(tmp.length() &amp;lt; b) tmp += str;

        int ans = 0;

        for(int i=a-1; i&amp;lt;b; i++)
            if(tmp[i] == 'B') ans++;

        cout &amp;lt;&amp;lt; &quot;Case #&quot; &amp;lt;&amp;lt; t &amp;lt;&amp;lt; &quot;: &quot; &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 15121번 : Star Arrangements&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N이 주어질 때, 두 수의 차이가 1 이내이면서 두 수를 반복해서 더하다가 N이 되도록 하는 두 수의 조합을 모두 구하는 문제이다. (이 때 첫 번째 수는 두 번째 수보다 작으면 안된다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이중 for문을 돌리면서 모두 체크해보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;i는 2 ~ N에서 돌려주고 j는 1 ~ N에서 돌리되, i + j가 N 이하이면서 i와 j가 1 이내의 차이를 가지면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 sum 값에 i와 j를 번갈아가면서 더하다가 정확히 N이 되면 i와 j는 하나의 답이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661831561231&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    cout &amp;lt;&amp;lt; N &amp;lt;&amp;lt; &quot;:\n&quot;;

    for(int i=2; i&amp;lt;=N; i++)
        for(int j=1; j&amp;lt;=i &amp;amp;&amp;amp; i+j&amp;lt;=N; j++) {
            if(abs(i - j) &amp;gt; 1) continue;

            int sum = 0;

            while(true) {
                if(sum + i &amp;lt;= N) sum += i;
                else break;

                if(sum + j &amp;lt;= N) sum += j;
                else break;
            }

            if(sum == N) cout &amp;lt;&amp;lt; i &amp;lt;&amp;lt; &quot;,&quot; &amp;lt;&amp;lt; j &amp;lt;&amp;lt; &quot;\n&quot;;
        }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 15494번 : Davor&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;월요일에는 x원, 화요일에는 x + y원, ... , 일요일에는 x + 6y원을 저축하여 52주동안 저축 후 정확히 N원을 모았을 때, x와 y를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;52주동안 모인 돈은 7*52x + 21*52y이므로, for문으로 이것이 N이 되는 (x, y)를 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나의 경우에는 x를 고정하고 y가 존재하는지 확인하는 방식으로 풀었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661846203617&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    for(int i=100; i&amp;gt;=0; i--) {
        if(N - i*7*52 &amp;gt; 0 &amp;amp;&amp;amp; (N - i*7*52) % (21*52) == 0) {
            cout &amp;lt;&amp;lt; i &amp;lt;&amp;lt; &quot;\n&quot;;
            cout &amp;lt;&amp;lt; (N - i*7*52) / (21*52) &amp;lt;&amp;lt; &quot;\n&quot;;
            break;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 15593번 : Lifeguards (Bronze)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N마리의 소 각각이 a ~ b초 사이에 구조 활동을 할 수 있을 때, 1마리를 빼고 나머지가 가능한 최대 구조 활동의 시간을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3중 for문을 이용하여 한 마리씩 제거해보면서 각 소의 a ~ b 부분을 check 해주고, 마지막에 check 된 값들을 count 하면서 그 count 값의 최댓값을 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661846543788&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;pair&amp;lt;int, int&amp;gt;&amp;gt; v(N);

    for(int i=0; i&amp;lt;N; i++)
        cin &amp;gt;&amp;gt; v[i].first &amp;gt;&amp;gt; v[i].second;

    int ans = 0;

    for(int i=0; i&amp;lt;N; i++) {
        vector&amp;lt;bool&amp;gt; u(1001);

        for(int j=0; j&amp;lt;N; j++) {
            if(j == i) continue;

            for(int k=v[j].first; k&amp;lt;v[j].second; k++) u[k] = true;
        }

        int cnt = 0;

        for(int j=0; j&amp;lt;=1000; j++)
            if(u[j]) cnt++;

        ans = max(ans, cnt);
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 16306번 : Cardboard Container&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가로, 세로, 높이가 정수이고 부피가 N인 직육면체 중 표면적이 가장 작은 것의 표면적을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3중 for문을 쓰되 모든 수를 조사하면 쓰면 시간 초과에 걸리므로, 수가 N으로 나누어 떨어지는 경우만 더 탐색하도록 구현해주면 빠른 시간에 풀이할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661847306868&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    int ans = INT_MAX;

    for(int i=1; i&amp;lt;=N; i++) {
        if(N % i != 0) continue;

        int jk = N / i;

        for(int j=1; j&amp;lt;=jk; j++) {
            if(jk % j != 0) continue;

            int k = jk / j;

            ans = min(ans, (i*j + j*k + k*i)*2);
        }
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 16412번 : Heir's Dilemma&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6자리 숫자 중에서 주어진 a 이상, b 이하이면서 6자리가 모두 다르고, 0을 포함하지 않으며, 각 자릿수의 숫자로 나누었을 때 나누어떨어지는 수의 개수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제에서 구해야 하는 수의 조건 자체를 모두 주었으므로, 주어진 조건을 조건문으로 구현하기만 하면 되는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661855527878&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

    int ans = 0;

    for(int i=a; i&amp;lt;=b; i++) {
        int tmp = i;

        vector&amp;lt;int&amp;gt; cnt(10);

        while(tmp &amp;gt; 0) {
            cnt[tmp % 10]++;

            tmp /= 10;
        }

        bool check = true;

        for(int j=0; j&amp;lt;10; j++)
            if(cnt[j] &amp;gt;= 2) check = false;

        if(cnt[0] &amp;gt;= 1) check = false;

        if(!check) continue;

        for(int j=1; j&amp;lt;10; j++) {
            if(cnt[j] == 0) continue;

            if(i % j != 0) check = false;
        }

        if(check) ans++;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 16847번 : Teenage Mutant&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1개의 문자열이 주어지고, N개의 조상 문자열이 주어질 때, 모든 조상 문자열과 다른 문자 위치의 개수를 구하는 문제이다. 모든 문자열의 길이는 M이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2중 for문으로 검사해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자리에 대해 먼저 for문을 0 ~ M-1으로 돌려주고, 각 자리에 대해 모든 조상과 같은 위치의 일치하는 문자가 하나라도 있는지 체크해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조건에 의해 약분을 할 필요가 없으므로 유클리드 호제법을 사용할 필요가 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661855626993&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    for(int t=1; t&amp;lt;=T; t++) {
        int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

        string str; cin &amp;gt;&amp;gt; str;

        vector&amp;lt;string&amp;gt; v(N);
        for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];

        int cnt = 0;

        for(int i=0; i&amp;lt;M; i++) {
            bool check = false;

            for(int j=0; j&amp;lt;N; j++)
                if(str[i] == v[j][i]) check = true;

            if(!check) cnt++;
        }

        cout &amp;lt;&amp;lt; &quot;Data Set &quot; &amp;lt;&amp;lt; t &amp;lt;&amp;lt; &quot;:\n&quot;;
        cout &amp;lt;&amp;lt; cnt &amp;lt;&amp;lt; &quot;/&quot; &amp;lt;&amp;lt; M &amp;lt;&amp;lt; &quot;\n\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 17889번 : Mars Window&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2018년 4월을 기준으로 26개월마다 적절한 발사 시기라고 할 때, 주어진 년에 적절한 발사 시기가 존재하는지 체크하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2018년 1월의 cnt 값을 1로 잡고, cnt 값을 매 월마다 1씩 추가하다가 cnt % 26 = 4이면 적절한 발사 시기에 해당한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661855667074&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    int cnt = 0;

    for(int i=2018; i&amp;lt;=10000; i++) {
        bool check = false;

        for(int j=1; j&amp;lt;=12; j++) {
            cnt++;

            if(cnt % 26 == 4) check = true;
        }

        if(i == N) {
            if(check) cout &amp;lt;&amp;lt; &quot;yes\n&quot;;
            else cout &amp;lt;&amp;lt; &quot;no\n&quot;;

            break;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 17924번 : Cooking Water&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제를 요약하여 설명하자면 주어진 N개의 구간에 대해, 모든 구간에 포함하는 숫자가 존재하는지 확인하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 수의 범위가 10,000 이하로 주어지기 때문에, 구간들을 벡터로 입력받고, 0 ~ 10,000 중에 모든 구간에 포함되는 숫자가 있는지 체크해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간 복잡도는 O(1e4 N)이 되고, 이는 통과하기에 넉넉하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661855754651&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;pair&amp;lt;int, int&amp;gt;&amp;gt; v(N);

    for(int i=0; i&amp;lt;N; i++)
        cin &amp;gt;&amp;gt; v[i].first &amp;gt;&amp;gt; v[i].second;

    for(int i=0; i&amp;lt;=1000; i++) {
        bool check = true;

        for(int j=0; j&amp;lt;N; j++)
            if(i &amp;lt; v[j].first || i &amp;gt; v[j].second) check = false;

        if(check) {
            cout &amp;lt;&amp;lt; &quot;gunilla has a point\n&quot;;
            return 0;
        }
    }

    cout &amp;lt;&amp;lt; &quot;edward is right\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 23389번 : 一般化うるう年&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 우리가 400년, 100년, 4년을 가지고 규칙에 따라 윤년을 정하는 것처럼 주어진 N개의 수를 가지고 l ~ r년 사이에 윤년이 몇 개인지 세는 문제인데, 번역이 제대로 안 돌아가서 이해가 잘 안된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무튼 문제에서 하라는대로 (년 수) % v[i] = 0이면서 i % 2 == 0이면 윤년이고, 또한 나누어떨어지는 v[i]가 없는 경우 N이 짝수면 윤년을 추가해주면 된다. (문제에서 하라는대로 구현하면 된다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661862490778&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    while(true) {
        int N, l, r; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; l &amp;gt;&amp;gt; r;
        if(N == 0 &amp;amp;&amp;amp; l == 0 &amp;amp;&amp;amp; r == 0) break;

        vector&amp;lt;int&amp;gt; v(N);
        for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];

        int ans = 0;

        for(int i=l; i&amp;lt;=r; i++) {
            bool check = false;

            for(int j=0; j&amp;lt;N; j++) {
                if(i % v[j] == 0) {
                    if(j % 2 == 0) ans++;

                    check = true;

                    break;
                }
            }

            if(!check &amp;amp;&amp;amp; N % 2 == 0) ans++;
        }

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 22825번 : Fermat's Last Theorem&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주어진 자연수 z에 대해, z^3 - (x^3 + y^3)의 0보다 큰 최솟값을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2중 반복문을 돌려서 풀 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661862723674&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    while(true) {
        int N; cin &amp;gt;&amp;gt; N;
        if(N == 0) break;

        int ans = N*N*N;

        for(int i=1; i*i*i&amp;lt;=N*N*N; i++)
            for(int j=1; i*i*i+j*j*j&amp;lt;=N*N*N; j++)
                ans = min(ans, N*N*N - (i*i*i + j*j*j));

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 2508번 : 사탕 박사 고창영&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주어진 N x M 문자 배열에서 다음의 두 가지 도형의 개수를 찾는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661863782148&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt;o&amp;lt;

v
o
^&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이중 for문을 2번 사용하여 먼저 가로로 스캔을 해주고, 그 다음 세로로 다시 스캔해주면서 세면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661863803386&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    while(T--) {
        int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

        vector&amp;lt;vector&amp;lt;char&amp;gt;&amp;gt; v(N, vector&amp;lt;char&amp;gt;(M));

        for(int i=0; i&amp;lt;N; i++)
            for(int j=0; j&amp;lt;M; j++) cin &amp;gt;&amp;gt; v[i][j];

        int ans = 0;

        for(int i=0; i&amp;lt;N; i++)
            for(int j=0; j&amp;lt;M-2; j++)
                if(v[i][j] == '&amp;gt;' &amp;amp;&amp;amp; v[i][j+1] == 'o' &amp;amp;&amp;amp; v[i][j+2] == '&amp;lt;') ans++;

        for(int i=0; i&amp;lt;N-2; i++)
            for(int j=0; j&amp;lt;M; j++)
                if(v[i][j] == 'v' &amp;amp;&amp;amp; v[i+1][j] == 'o' &amp;amp;&amp;amp; v[i+2][j] == '^') ans++;

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/알고리즘 공부 내용 정리</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/624</guid>
      <comments>https://restudycafe.tistory.com/624#entry624comment</comments>
      <pubDate>Tue, 30 Aug 2022 11:55:23 +0900</pubDate>
    </item>
    <item>
      <title>백준 BOJ 알고리즘 공부 일기 (오프라인 쿼리 포함) 220829</title>
      <link>https://restudycafe.tistory.com/623</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 13306번 : 트리&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;오프라인 쿼리, 분리 집합&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리와 쿼리가 주어질 때, 각 쿼리에 대해 특정 간선을 지우거나 두 정점이 연결 상태인지를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오프라인 쿼리 문제인데, &lt;b&gt;오프라인 쿼리&lt;/b&gt; 문제는 주어진 쿼리 순서대로 처리를 하는 것이 아니라 문제를 효율적으로 풀 수 있게끔 &lt;span style=&quot;color: #ee2323;&quot;&gt;쿼리의 순서를 재배치하여 풀이하는 방식&lt;/span&gt;의 문제를 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 이 문제에서는 쿼리를 역순으로 배치한 뒤 분리 집합으로 노드들을 연결해가면서 풀어주면 아주 쉽게 풀 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역순 배치가 아닌 다른 순서대로 푸는 문제도 있는 것 같던데 조만간 공부할 것이다. (예를 들면 mo's 알고리즘. 지금 제곱근 분할법 문제 몇 개는 풀어봤는데 mo's를 공부 안해서 못 풀고 있는 문제들이 많다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661779634510&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { int Q, a, b; };

vector&amp;lt;int&amp;gt; v;

int f(int x) {
    if(v[x] == x) return x;
    else return v[x] = f(v[x]);
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    vector&amp;lt;int&amp;gt; p(N+1);
    for(int i=2; i&amp;lt;=N; i++) cin &amp;gt;&amp;gt; p[i];

    M += N-1;

    vector&amp;lt;s&amp;gt; q(M);

    for(int i=0; i&amp;lt;M; i++) {
        cin &amp;gt;&amp;gt; q[i].Q;

        if(q[i].Q == 0) cin &amp;gt;&amp;gt; q[i].a;
        else if(q[i].Q == 1) cin &amp;gt;&amp;gt; q[i].a &amp;gt;&amp;gt; q[i].b;
    }

    v.resize(N+1);
    for(int i=1; i&amp;lt;=N; i++) v[i] = i;

    stack&amp;lt;bool&amp;gt; ans;

    for(int i=M-1; i&amp;gt;=0; i--) {
        if(q[i].Q == 0) {
            if(f(q[i].a) != f(p[q[i].a])) v[f(q[i].a)] = f(p[q[i].a]);
        }
        else if(q[i].Q == 1) {
            if(f(q[i].a) == f(q[i].b)) ans.push(true);
            else ans.push(false);
        }
    }

    while(!ans.empty()) {
        if(ans.top()) cout &amp;lt;&amp;lt; &quot;YES\n&quot;;
        else cout &amp;lt;&amp;lt; &quot;NO\n&quot;;

        ans.pop();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 10775번 : 공항&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;분리 집합&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 게이트가 있고, M개의 비행기가 각각 u_i번 이하의 게이트에 도킹할 수 있다고 할 때, 주어진 입력 순서대로 비행기가 도킹한다면 최대로 도킹할 수 있는 비행기의 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리디하게 접근하여 u_i 이하의 도킹이 가능한 가장 큰 번호의 게이트에 도킹을 해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음, 같은 번호의 게이트에 비행기가 들어올 경우 그 이하의 최대 번호로 연결을 효율적으로 해주어야 하는데 여기서 분리 집합을 사용하면 수월하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;f(u_i)번 게이트에 도킹 후 f(u_i)값을 f(u_i) - 1로 해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;한 번 parent로 이동했을 때 그 게이트가 이미 차 있다고 하더라도 해당 게이트의 parent 역시 다른 게이트로 연결되어 있을 것이기 때문에 빈 게이트를 효율적으로 찾아줄 수가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도킹을 계속 하다가 만약 f(u_i) = 0일 경우 도킹이 더 이상 불가능한 것이므로 지금까지 연결한 비행기의 개수로 답을 얻어주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661744889320&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;int&amp;gt; v;

int f(int x) {
    if(v[x] == x) return x;
    else return v[x] = f(v[x]);
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    v.resize(N+1);
    for(int i=1; i&amp;lt;=N; i++) v[i] = i;

    int ans = 0;

    vector&amp;lt;int&amp;gt; u(M);
    for(int i=0; i&amp;lt;M; i++) cin &amp;gt;&amp;gt; u[i];

    for(int i=0; i&amp;lt;M; i++) {
        int x = u[i];

        if(f(x) == 0) break;

        v[f(x)] = f(x) - 1;
        ans++;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 1440번 : 타임머신&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시, 분, 초가 주어질 때 시, 분, 초의 순서를 바꾸어 (그대로인 것 포함) 읽어도 시, 분, 초의 범위에 해당하는 것의 개수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;next_permutation으로 3!가지 경우를 모두 확인해보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 이 문제의 경우 두 값이 같은 경우도 있는데 next_permutation 함수는 이 경우를 건너뛰므로 모두 다른 값을 가지는 벡터 하나를 추가로 이용해주는 방법 등을 사용해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661761946933&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    vector&amp;lt;int&amp;gt; v(3);

    char c;

    cin &amp;gt;&amp;gt; v[0] &amp;gt;&amp;gt; c &amp;gt;&amp;gt; v[1] &amp;gt;&amp;gt; c &amp;gt;&amp;gt; v[2];

    vector&amp;lt;int&amp;gt; u(3);
    u[0] = 0, u[1] = 1, u[2] = 2;

    int ans = 0;

    while(true) {
        if(v[u[0]] &amp;gt;= 1 &amp;amp;&amp;amp; v[u[0]] &amp;lt;= 12 &amp;amp;&amp;amp; v[u[1]] &amp;gt;= 0 &amp;amp;&amp;amp; v[u[1]] &amp;lt;= 59 &amp;amp;&amp;amp; v[u[2]] &amp;gt;= 0 &amp;amp;&amp;amp; v[u[2]] &amp;lt;= 59) ans++;

        if(!next_permutation(u.begin(), u.end())) break;
   }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 7637번 : AAAAHH! Overbooked!&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;24시간짜리 시간으로 주어진 N개의 시간 범위에 대해, 겹치는 것이 있는지 확인하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;24 x 60짜리 크기의 bool 변수를 이용하여 체크를 일일이 해주면서 새로 체크할 값에 이미 체크가 하나라도 되어있다면 conflict를, 그렇지 않다면 no conflict를 출력해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661772824341&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    while(true) {
        int N; cin &amp;gt;&amp;gt; N;
        if(N == 0) break;

        vector&amp;lt;bool&amp;gt; v(24*60);
        bool check = true;

        while(N--) {
            string str; cin &amp;gt;&amp;gt; str;

            int a = stoi(str.substr(0, 2));
            int b = stoi(str.substr(3, 2));
            int c = stoi(str.substr(6, 2));
            int d = stoi(str.substr(9, 2));

            for(int i=a*60+b; i&amp;lt;c*60+d; i++) {
                if(v[i]) check = false;

                v[i] = true;
            }
        }

        if(check) cout &amp;lt;&amp;lt; &quot;no conflict\n&quot;;
        else cout &amp;lt;&amp;lt; &quot;conflict\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 8676번 : Figury&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주어진 N개의 수에 대해 3개 연속으로 다른 수가 나오는 경우가 있는지 체크하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 3개씩 묶어서 일일이 확인해보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661773245744&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;int&amp;gt; v(N);
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];

    bool check = false;

    for(int i=2; i&amp;lt;N; i++)
        if(v[i] != v[i-1] &amp;amp;&amp;amp; v[i-1] != v[i-2] &amp;amp;&amp;amp; v[i-2] != v[i]) check = true;

    if(check) cout &amp;lt;&amp;lt; &quot;TAK\n&quot;;
    else cout &amp;lt;&amp;lt; &quot;NIE\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 9151번 : Starship Hakodate-maru&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N 이하이면서 가장 큰 a^3 + b x (b+1) x (b+2) / 6의 값을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2중 for문으로 N 이하의 범위에서 가능한 모든 조합을 다 확인해보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661776369379&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    while(true) {
        int N; cin &amp;gt;&amp;gt; N;
        if(N == 0) break;

        int ans = 0;

        for(int i=0; i*i*i&amp;lt;=N; i++)
            for(int j=0; i*i*i+j*(j+1)*(j+2)/6&amp;lt;=N; j++) ans = max(ans, i*i*i + j*(j+1)*(j+2)/6);

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 9182번 : Biorhythms&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특성 a는 23일마다, 특성 b는 28일마다, 특성 c는 33일마다 발현되며 하나의 테스트케이스에 각 특성이 발현된 날짜, 그리고 현재 날짜가 주어질 때 다음 날부터 세 특성이 모두 발현되는 날 중 가장 가까운 날까지의 기간을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력이 a b c d로 들어온다고 해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 x &amp;gt; d인 x에 대해 x % 23 = a % 23이고, x % 28 = b % 28이고, x % 33 = c % 23이라면 x는 d일 이후 세 특성이 모두 발현되는 날이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 이러한 x 중 가장 작은 것을 답으로 얻어주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661778043990&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    for(int t=1; ; t++) {
        int a, b, c, d; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b &amp;gt;&amp;gt; c &amp;gt;&amp;gt; d;
        if(a == -1 &amp;amp;&amp;amp; b == -1 &amp;amp;&amp;amp; c == -1 &amp;amp;&amp;amp; d == -1) break;

        for(int i=d+1; i&amp;lt;=21252; i++) {
            if(i % 23 == a % 23 &amp;amp;&amp;amp; i % 28 == b % 28 &amp;amp;&amp;amp; i % 33 == c % 33) {
                cout &amp;lt;&amp;lt; &quot;Case &quot; &amp;lt;&amp;lt; t &amp;lt;&amp;lt; &quot;: the next triple peak occurs in &quot; &amp;lt;&amp;lt; i - d &amp;lt;&amp;lt; &quot; days.\n&quot;;
                break;
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 9377번 : String LD&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 문자열에 대해, 각 문자열의 맨 왼쪽 문자를 지우는 연산을 다음이 되기 전까지 반복한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 문자열의 길이가 1인 것이 발생&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 두 문자열이 같은 것이 발생&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때, 연산을 최대 몇 번 수행할 수 있는지 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 1번 연산을 수행하여 같은 문자열이 발생한다면 답은 0이다. (발생 이전까지만 반복해야하므로)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조건 그대로 체크만 해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 문자열이 있는 것은 sort 해준 뒤 v[i-1]과 v[i]를 비교해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 두 문자열이 같은 것이 발생했을 경우는 이미 연산을 수행한 이후이므로 연산 수행 횟수를 잘 계산해서 구해주어야 한다. (0번이면 상관 없지만, 1번 이상인 경우는 1 빼고 구해주어야 함)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661778564563&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    while(true) {
        int N; cin &amp;gt;&amp;gt; N;
        if(N == 0) break;

        vector&amp;lt;string&amp;gt; v(N);
        for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];

        for(int i=0; ; i++) {
            sort(v.begin(), v.end());

            bool check = false;

            for(int j=0; j&amp;lt;N; j++)
                if(v[j].length() == 1) check = true;

            for(int j=1; j&amp;lt;N; j++)
                if(v[j] == v[j-1]) check = true;

            if(check) {
                cout &amp;lt;&amp;lt; i &amp;lt;&amp;lt; &quot;\n&quot;;
                break;
            }

            for(int j=0; j&amp;lt;N; j++)
                v[j] = v[j].substr(1, v[j].length()-1);

            sort(v.begin(), v.end());

            check = false;

            for(int j=1; j&amp;lt;N; j++)
                if(v[j] == v[j-1]) check = true;

            if(check) {
                cout &amp;lt;&amp;lt; i &amp;lt;&amp;lt; &quot;\n&quot;;
                break;
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 9161번 : Sir&amp;nbsp;Bedavere&amp;rsquo;s&amp;nbsp;Bogus&amp;nbsp;Division&amp;nbsp;Solutions&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 숫자의 맨 뒷자리와 다른 숫자의 맨 앞자리가 같은3자리 숫자 abc와 cde가 있을 때, 공통되는 숫자를 지워 ab, de를 만들었을 때 abc / cde = ab / de인 수의 순서쌍을 모두 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;abc를 100 ~ 999, cde도 100 ~ 999 사이의 모든 경우를 확인해보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661759751972&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    for(int i=100; i&amp;lt;=999; i++)
        for(int j=100; j&amp;lt;=999; j++) {
            if(i % 10 != j / 100) continue;
            if(i % 111 == 0) continue;

            int a = i, b = j, c = i / 10, d = j % 100;

            if(a * d == b * c)
                cout &amp;lt;&amp;lt; a &amp;lt;&amp;lt; &quot; / &quot; &amp;lt;&amp;lt; b &amp;lt;&amp;lt; &quot; = &quot; &amp;lt;&amp;lt; c &amp;lt;&amp;lt; &quot; / &quot; &amp;lt;&amp;lt; d &amp;lt;&amp;lt; &quot;\n&quot;;
        }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 9664번 : NASLJEDSTVO&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;몇 개의 물건 중에서 1/N만큼을 (내림) 가져가고 남은 것이 M개일 때, 원래 있었던 것으로 가능한 최소/최대 물건의 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내림 처리를 하고 가져갔기 때문에 역으로 연산하기가 쉽지 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 범위를 넉넉하게 잡아서 x - x/N = M이면 x에 대해 최대, 최소를 갱신해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661760172734&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    int Min = INT_MAX, Max = INT_MIN;

    for(int i=1; i&amp;lt;=1e3; i++) {
        if(i - i/N == M) {
            Min = min(Min, i);
            Max = max(Max, i);
        }
    }

    cout &amp;lt;&amp;lt; Min &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; Max &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 19751번 : Fractification&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네 정수 a, b, c, d가 주어질 때 a/b + c/d가 최소가 되도록 값들을 적절히 swap하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;next_permutation 함수를 이용하여 4! 가지의 경우를 모두 비교해보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실수 연산에서 오차가 발생하지 않을까 했는데 다행히 극악의 테스트케이스는 없는 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661760516727&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    vector&amp;lt;double&amp;gt; v(4);

    for(int i=0; i&amp;lt;4; i++) cin &amp;gt;&amp;gt; v[i];

    sort(v.begin(), v.end());

    vector&amp;lt;double&amp;gt; u;
    double Min = INT_MAX;

    while(true) {
        if(v[0] / v[1] + v[2] / v[3] &amp;lt; Min) {
            Min = v[0] / v[1] + v[2] / v[3];

            u = v;
        }

        if(!next_permutation(v.begin(), v.end())) break;
    }

    for(int i=0; i&amp;lt;4; i++) cout &amp;lt;&amp;lt; (int)u[i] &amp;lt;&amp;lt; &quot; &quot;;
    cout &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 24348번 : ИЗРАЗ&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3개의 수가 주어질 때, +, -, * 를 최대 한 번만 사용하여 만들 수 있는 최댓값을 구하는 문제이다. (세 수의 순서를 바꿔도 된다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;next_permutation을 이용하여 세 수의 순서를 바꾸고, 주어지는 수가 0 이상이므로 +와 *만을 가지고 모든 조합을 비교해보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661760921493&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    vector&amp;lt;int&amp;gt; v(3);
    for(int i=0; i&amp;lt;3; i++) cin &amp;gt;&amp;gt; v[i];

    sort(v.begin(), v.end());

    int ans = 0;

    while(true) {
        ans = max(ans, v[0] + v[1] * v[2]);
        ans = max(ans, v[0] * v[1] + v[2]);

        if(!next_permutation(v.begin(), v.end())) break;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/알고리즘 공부 내용 정리</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/623</guid>
      <comments>https://restudycafe.tistory.com/623#entry623comment</comments>
      <pubDate>Mon, 29 Aug 2022 12:53:06 +0900</pubDate>
    </item>
    <item>
      <title>선분 교차 판정 알고리즘 문제 풀이 정리 220828</title>
      <link>https://restudycafe.tistory.com/622</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 20149번 : 선분 교차 3&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;기하학, 선분 교차 판정&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 선분의 끝 점의 좌표가 주어질 때, 두 선분의 교차 여부를 구하고, 만약 한 점에서만 교차한다면 그 좌표를 오차 범위 1e-9 이내로 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CCW 값들을 가지고 잘 푸는 것인지는 당연히 아는데, 케이스를 어떻게 나눠야 깔끔하게 정리되는지 도저히 구상이 안 되어서 다른 블로그를 보고 공부했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인적으로는 &lt;a href=&quot;https://cocoon1787.tistory.com/489&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이 링크&lt;/a&gt;에 설명이 가장 잘 되어있다고 생각하고 또 여기서 대부분의 코드를 참고했다. (20220829 수정 : 링크가 잘못 걸려 있었다;;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 교차 판정을 먼저 해보자. 점은 a, b, c, d의 네 점이 주어지고 a, b를 잇는 선분과 c, d를 잇는 선분이 있다고 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ccw 값을 이용하면 세 점의 방향 배치를 알 수 있다. (ccw &amp;gt; 0이면 세 점이 시계 반대 방향, ccw &amp;lt; 0이면 시계 방향, ccw = 0이면 세 점은 일직선 상에 있다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ccw(a, b, c) x ccw(a, b, d) 값과 ccw(c, d, a) x ccw(c, d, b) 값이 둘 다 0이라면 두 선분은 평행이거나 끝 점이 일치하는 경우이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;a와 b, 그리고 c와 d를 좌표가 증가하게 정렬을 일단 해준 다음에 생각해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1) a &amp;le; d인데 b &amp;ge; c라면 ab의 오른쪽 끝과 cd의 왼쪽 끝이 겹친다는 뜻이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2) 그게 아니라면 두 점은 교차하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ccw(a, b, c) x ccw(a, b, d) 값과 ccw(c, d, a) x ccw(c, d, b)&lt;span&gt; 값 중 하나라도 0이 아니라면 다음과 같이 나눌 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;(1) 두 값이 모두 0 이하라면 두 선분은 가운데가 교차하거나, 또는 한 선분의 끝점이 다른 선분의 가운데에 위치하는 경우이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;(2) 그게 아니라면 두 선분은 교차하지 않는다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;이제 두 선분이 교차하는 경우에 한해 좌표를 구해주어야 하는데, 수학 문제를 손으로 푸는게 아닌 수식을 코드로 작성할 것이기 때문에 다음의 공식을 사용하는 것이 가장 편하다. (식이 길더라도 변수를 많이 안 쓰고 처리하는 편이 수월하다는 이야기)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(교점의 좌표) = (((x1y2 - y1x2)(x3 - x4) - (x1 - x2)(x3y4 - y3x4)) / ((x1 - x2)(y3 - y4) - (y1 - y2)(x3 - x4)), ((x1y2 - y1x2)(y3 - y4) - (y1 - y2)(x3y4 - y3x4)) / ((x1 - x2)(y3 - y4) - (y1 - y2)(x3 - x4)))&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 분모가 0인 경우인데, 이 경우에는 다음의 두 경우로 나뉜다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1) b = c이고 a &amp;le; c이면 : 점 b = c에서 교차하는 것이므로 b의 좌표나 c의 좌표 둘 중 하나를 출력해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2) a = d이고 c &amp;ge; a이면 : 점 a = d에서 교차하는 것이므로 a의 좌표나 d의 좌표 둘 중 하나를 출력해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 모든 경우가 해결이 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드는 아래의 접은 글에 정리되어있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661618262227&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { int x, y; };

bool operator== (s a, s b) {
    if(a.x == b.x &amp;amp;&amp;amp; a.y == b.y) return true;
    else return false;
}
bool operator&amp;gt;= (s a, s b) {
    if(a.x &amp;gt; b.x || (a.x == b.x &amp;amp;&amp;amp; a.y &amp;gt;= b.y)) return true;
    else return false;
}
bool operator&amp;lt;= (s a, s b) {
    if(a.x &amp;lt; b.x || (a.x == b.x &amp;amp;&amp;amp; a.y &amp;lt;= b.y)) return true;
    else return false;
}
bool operator&amp;gt; (s a, s b) {
    if(a.x &amp;gt; b.x || (a.x == b.x &amp;amp;&amp;amp; a.y &amp;gt; b.y)) return true;
    else return false;
}
bool operator&amp;lt; (s a, s b) {
    if(a.x &amp;lt; b.x || (a.x == b.x &amp;amp;&amp;amp; a.y &amp;lt; b.y)) return true;
    else return false;
}

int ccw(s a, s b, s c) {
    int val = a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y);

    if(val == 0) return 0;
    else if(val &amp;gt; 0) return 1;
    else if(val &amp;lt; 0) return -1;
}

void coor(s a, s b, s c, s d) {
    double X = (a.x * b.y - a.y * b.x) * (c.x - d.x) - (a.x - b.x) * (c.x * d.y - c.y * d.x);
    double Y = (a.x * b.y - a.y * b.x) * (c.y - d.y) - (a.y - b.y) * (c.x * d.y - c.y * d.x);
    double div = (a.x - b.x) * (c.y - d.y) - (a.y - b.y) * (c.x - d.x);

    if(div == 0) {
        if(b == c &amp;amp;&amp;amp; a &amp;lt;= c) cout &amp;lt;&amp;lt; b.x &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; b.y &amp;lt;&amp;lt; &quot;\n&quot;;
        else if(a == d &amp;amp;&amp;amp; c &amp;lt;= a) cout &amp;lt;&amp;lt; a.x &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; a.y &amp;lt;&amp;lt; &quot;\n&quot;;
    }
    else cout &amp;lt;&amp;lt; X / div &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; Y / div &amp;lt;&amp;lt; &quot;\n&quot;;
}

void inter(s a, s b, s c, s d) {
    int val1 = ccw(a, b, c) * ccw(a, b, d);
    int val2 = ccw(c, d, a) * ccw(c, d, b);

    if(val1 == 0 &amp;amp;&amp;amp; val2 == 0) {
        if(a &amp;gt; b) swap(a, b);
        if(c &amp;gt; d) swap(c, d);

        if(a &amp;lt;= d &amp;amp;&amp;amp; b &amp;gt;= c) {
            cout &amp;lt;&amp;lt; 1 &amp;lt;&amp;lt; &quot;\n&quot;;
            coor(a, b, c, d);
        }
        else cout &amp;lt;&amp;lt; 0 &amp;lt;&amp;lt; &quot;\n&quot;;
    }
    else {
        if(val1 &amp;lt;= 0 &amp;amp;&amp;amp; val2 &amp;lt;= 0) {
            cout &amp;lt;&amp;lt; 1 &amp;lt;&amp;lt; &quot;\n&quot;;
            coor(a, b, c, d);
        }
        else cout &amp;lt;&amp;lt; 0 &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    vector&amp;lt;s&amp;gt; p(4);
    for(int i=0; i&amp;lt;4; i++) cin &amp;gt;&amp;gt; p[i].x &amp;gt;&amp;gt; p[i].y;

    cout &amp;lt;&amp;lt; fixed;
    cout.precision(9);

    inter(p[0], p[1], p[2], p[3]);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 10255번 : 교차점&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;기하학, 선분 교차 판정&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직사각형의 왼쪽 아래 좌표와 오른쪽 위 좌표, 그리고 선분이 주어졌을 때 선분과 직사각형의 교점의 개수를 구하는 문제이다. (만약 무수히 많은 점이 겹친다면 4를 출력한다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직사각형의 4개의 변 각각에 대해 선분과의 교차 여부를 확인해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 하나라도 선분이 겹치는 경우가 있으면 4를 출력해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 직사각형의 꼭짓점과 선분이 만나는 경우인데 이 경우에는 만난 꼭짓점의 개수만큼 다시 빼주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661698328355&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { int x, y; };

bool operator== (s a, s b) {
    if(a.x == b.x &amp;amp;&amp;amp; a.y == b.y) return true;
    else return false;
}
bool operator&amp;gt;= (s a, s b) {
    if(a.x &amp;gt; b.x || (a.x == b.x &amp;amp;&amp;amp; a.y &amp;gt;= b.y)) return true;
    else return false;
}
bool operator&amp;lt;= (s a, s b) {
    if(a.x &amp;lt; b.x || (a.x == b.x &amp;amp;&amp;amp; a.y &amp;lt;= b.y)) return true;
    else return false;
}
bool operator&amp;gt; (s a, s b) {
    if(a.x &amp;gt; b.x || (a.x == b.x &amp;amp;&amp;amp; a.y &amp;gt; b.y)) return true;
    else return false;
}
bool operator&amp;lt; (s a, s b) {
    if(a.x &amp;lt; b.x || (a.x == b.x &amp;amp;&amp;amp; a.y &amp;lt; b.y)) return true;
    else return false;
}

int ccw(s a, s b, s c) {
    int val = a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y);

    if(val == 0) return 0;
    else if(val &amp;gt; 0) return 1;
    else if(val &amp;lt; 0) return -1;
}

bool cross, overlap;
double cx, cy;

void coor(s a, s b, s c, s d) {
    double X = (a.x * b.y - a.y * b.x) * (c.x - d.x) - (a.x - b.x) * (c.x * d.y - c.y * d.x);
    double Y = (a.x * b.y - a.y * b.x) * (c.y - d.y) - (a.y - b.y) * (c.x * d.y - c.y * d.x);
    double div = (a.x - b.x) * (c.y - d.y) - (a.y - b.y) * (c.x - d.x);

    if(div == 0) {
        if(b == c &amp;amp;&amp;amp; a &amp;lt;= c) cx = b.x, cy = b.y, overlap = false;
        else if(a == d &amp;amp;&amp;amp; c &amp;lt;= a) cx = a.x, cy = a.y, overlap = false;
        else overlap = true;
    }
    else cx = X / div, cy = Y / div, overlap = false;
}

void inter(s a, s b, s c, s d) {
    int val1 = ccw(a, b, c) * ccw(a, b, d);
    int val2 = ccw(c, d, a) * ccw(c, d, b);

    if(val1 == 0 &amp;amp;&amp;amp; val2 == 0) {
        if(a &amp;gt; b) swap(a, b);
        if(c &amp;gt; d) swap(c, d);

        if(a &amp;lt;= d &amp;amp;&amp;amp; b &amp;gt;= c) {
            cross = true;
            coor(a, b, c, d);
        }
        else cross = false;
    }
    else {
        if(val1 &amp;lt;= 0 &amp;amp;&amp;amp; val2 &amp;lt;= 0) {
            cross = true;
            coor(a, b, c, d);
        }
        else cross = false;
    }
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    cout &amp;lt;&amp;lt; fixed;
    cout.precision(9);

    int T; cin &amp;gt;&amp;gt; T;

    while(T--) {
        vector&amp;lt;s&amp;gt; v(6);

        cin &amp;gt;&amp;gt; v[0].x &amp;gt;&amp;gt; v[0].y &amp;gt;&amp;gt; v[2].x &amp;gt;&amp;gt; v[2].y;
        cin &amp;gt;&amp;gt; v[4].x &amp;gt;&amp;gt; v[4].y &amp;gt;&amp;gt; v[5].x &amp;gt;&amp;gt; v[5].y;

        v[1].x = v[2].x, v[1].y = v[0].y;
        v[3].x = v[0].x, v[3].y = v[2].y;

        int cnt = 0, ver = 0;
        bool inf = false;

        for(int i=0; i&amp;lt;4; i++) {
            inter(v[i], v[(i+1)%4], v[4], v[5]);

            if(cross &amp;amp;&amp;amp; overlap) inf = true;
            else if(cross) {
                bool check = false;

                for(int i=0; i&amp;lt;4; i++)
                    if(cx == v[i].x &amp;amp;&amp;amp; cy == v[i].y) check = true;

                if(check) ver++;

                cnt++;
            }
        }

        if(inf) cout &amp;lt;&amp;lt; 4 &amp;lt;&amp;lt; &quot;\n&quot;;
        else {
            cnt -= ver/2;

            cout &amp;lt;&amp;lt; cnt &amp;lt;&amp;lt; &quot;\n&quot;;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 16491번 : 대피소 찾기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;기하학, 선분 교차 판정, 브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 로봇이 N개의 대피소로 한 로봇 당 하나의 대피소에 이동할 때, 직선으로 이동하는 로봇들이 서로 동선이 겹치지 않게 하기 위해 각각 이동해야하는 대피소 번호를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 브루트포스 방식으로 로봇들을 각 대피소에 가능한 모든 매치를 해주고, 각 매치에 대해서 두 지점을 연결한 선분 N개가 서로 교차하는지 체크해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나의 경우에는 매치하는 과정을 next_permutation을 이용해서 풀었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661697380850&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { int x, y; };

bool operator== (s a, s b) {
    if(a.x == b.x &amp;amp;&amp;amp; a.y == b.y) return true;
    else return false;
}
bool operator&amp;gt;= (s a, s b) {
    if(a.x &amp;gt; b.x || (a.x == b.x &amp;amp;&amp;amp; a.y &amp;gt;= b.y)) return true;
    else return false;
}
bool operator&amp;lt;= (s a, s b) {
    if(a.x &amp;lt; b.x || (a.x == b.x &amp;amp;&amp;amp; a.y &amp;lt;= b.y)) return true;
    else return false;
}
bool operator&amp;gt; (s a, s b) {
    if(a.x &amp;gt; b.x || (a.x == b.x &amp;amp;&amp;amp; a.y &amp;gt; b.y)) return true;
    else return false;
}
bool operator&amp;lt; (s a, s b) {
    if(a.x &amp;lt; b.x || (a.x == b.x &amp;amp;&amp;amp; a.y &amp;lt; b.y)) return true;
    else return false;
}

int ccw(s a, s b, s c) {
    int val = a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y);

    if(val == 0) return 0;
    else if(val &amp;gt; 0) return 1;
    else if(val &amp;lt; 0) return -1;
}

bool cross, overlap;
double cx, cy;

void coor(s a, s b, s c, s d) {
    double X = (a.x * b.y - a.y * b.x) * (c.x - d.x) - (a.x - b.x) * (c.x * d.y - c.y * d.x);
    double Y = (a.x * b.y - a.y * b.x) * (c.y - d.y) - (a.y - b.y) * (c.x * d.y - c.y * d.x);
    double div = (a.x - b.x) * (c.y - d.y) - (a.y - b.y) * (c.x - d.x);

    if(div == 0) {
        if(b == c &amp;amp;&amp;amp; a &amp;lt;= c) cx = b.x, cy = b.y, overlap = false;
        else if(a == d &amp;amp;&amp;amp; c &amp;lt;= a) cx = a.x, cy = a.y, overlap = false;
        else overlap = true;
    }
    else cx = X / div, cy = Y / div, overlap = false;
}

void inter(s a, s b, s c, s d) {
    int val1 = ccw(a, b, c) * ccw(a, b, d);
    int val2 = ccw(c, d, a) * ccw(c, d, b);

    if(val1 == 0 &amp;amp;&amp;amp; val2 == 0) {
        if(a &amp;gt; b) swap(a, b);
        if(c &amp;gt; d) swap(c, d);

        if(a &amp;lt;= d &amp;amp;&amp;amp; b &amp;gt;= c) {
            cross = true;
            coor(a, b, c, d);
        }
        else cross = false;
    }
    else {
        if(val1 &amp;lt;= 0 &amp;amp;&amp;amp; val2 &amp;lt;= 0) {
            cross = true;
            coor(a, b, c, d);
        }
        else cross = false;
    }
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;s&amp;gt; v(N), u(N);
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i].x &amp;gt;&amp;gt; v[i].y;
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; u[i].x &amp;gt;&amp;gt; u[i].y;

    vector&amp;lt;int&amp;gt; w(N);
    for(int i=0; i&amp;lt;N; i++) w[i] = i;

    while(true) {
        bool check = true;

        for(int i=0; i&amp;lt;N; i++)
            for(int j=i+1; j&amp;lt;N; j++) {
                inter(v[i], u[w[i]], v[j], u[w[j]]);

                if(cross) check = false;
            }

        if(check) {
            for(int i=0; i&amp;lt;N; i++) cout &amp;lt;&amp;lt; w[i] + 1 &amp;lt;&amp;lt; &quot;\n&quot;;

            break;
        }

        if(!next_permutation(w.begin(), w.end())) break;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 2162번 : 선분 그룹&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;기하학, 선분 교차 판정, 분리 집합&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 선분이 주어지고 한 점 이상에서 교차하는 것은 같은 그룹이라고 할 때, 몇 개의 그룹이 존재하는지와 가장 큰 그룹의 크기를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;교차하는 선분들에 대해서, 분리 집합으로 같은 그룹으로 묶어주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 교차 여부만 판별하면 되는데 이것은 위에서 구현한 방식으로 해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661660712500&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { int x, y; };

bool operator== (s a, s b) {
    if(a.x == b.x &amp;amp;&amp;amp; a.y == b.y) return true;
    else return false;
}
bool operator&amp;gt;= (s a, s b) {
    if(a.x &amp;gt; b.x || (a.x == b.x &amp;amp;&amp;amp; a.y &amp;gt;= b.y)) return true;
    else return false;
}
bool operator&amp;lt;= (s a, s b) {
    if(a.x &amp;lt; b.x || (a.x == b.x &amp;amp;&amp;amp; a.y &amp;lt;= b.y)) return true;
    else return false;
}
bool operator&amp;gt; (s a, s b) {
    if(a.x &amp;gt; b.x || (a.x == b.x &amp;amp;&amp;amp; a.y &amp;gt; b.y)) return true;
    else return false;
}
bool operator&amp;lt; (s a, s b) {
    if(a.x &amp;lt; b.x || (a.x == b.x &amp;amp;&amp;amp; a.y &amp;lt; b.y)) return true;
    else return false;
}

int ccw(s a, s b, s c) {
    int val = a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y);

    if(val == 0) return 0;
    else if(val &amp;gt; 0) return 1;
    else if(val &amp;lt; 0) return -1;
}

bool cross, overlap;
double cx, cy;

void coor(s a, s b, s c, s d) {
    double X = (a.x * b.y - a.y * b.x) * (c.x - d.x) - (a.x - b.x) * (c.x * d.y - c.y * d.x);
    double Y = (a.x * b.y - a.y * b.x) * (c.y - d.y) - (a.y - b.y) * (c.x * d.y - c.y * d.x);
    double div = (a.x - b.x) * (c.y - d.y) - (a.y - b.y) * (c.x - d.x);

    if(div == 0) {
        if(b == c &amp;amp;&amp;amp; a &amp;lt;= c) cx = b.x, cy = b.y, overlap = false;
        else if(a == d &amp;amp;&amp;amp; c &amp;lt;= a) cx = a.x, cy = a.y, overlap = false;
        else overlap = true;
    }
    else cx = X / div, cy = Y / div, overlap = false;
}

void inter(s a, s b, s c, s d) {
    int val1 = ccw(a, b, c) * ccw(a, b, d);
    int val2 = ccw(c, d, a) * ccw(c, d, b);

    if(val1 == 0 &amp;amp;&amp;amp; val2 == 0) {
        if(a &amp;gt; b) swap(a, b);
        if(c &amp;gt; d) swap(c, d);

        if(a &amp;lt;= d &amp;amp;&amp;amp; b &amp;gt;= c) {
            cross = true;
            coor(a, b, c, d);
        }
        else cross = false;
    }
    else {
        if(val1 &amp;lt;= 0 &amp;amp;&amp;amp; val2 &amp;lt;= 0) {
            cross = true;
            coor(a, b, c, d);
        }
        else cross = false;
    }
}

vector&amp;lt;int&amp;gt; u;

int f(int x) {
    if(u[x] == x) return x;
    else return x = f(u[x]);
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    cout &amp;lt;&amp;lt; fixed;
    cout.precision(9);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;s&amp;gt; v(N*2);
    for(int i=0; i&amp;lt;N*2; i++) cin &amp;gt;&amp;gt; v[i].x &amp;gt;&amp;gt; v[i].y;

    u.resize(N);
    for(int i=0; i&amp;lt;N; i++) u[i] = i;

    for(int i=0; i&amp;lt;N; i++)
        for(int j=i+1; j&amp;lt;N; j++) {
            inter(v[i*2], v[i*2 + 1], v[j*2], v[j*2 + 1]);

            if(cross &amp;amp;&amp;amp; f(i) != f(j)) u[f(i)] = f(j);
        }

    vector&amp;lt;int&amp;gt; w;

    for(int i=0; i&amp;lt;N; i++) w.push_back(f(i));

    sort(w.begin(), w.end());
    w.erase(unique(w.begin(), w.end()), w.end());

    cout &amp;lt;&amp;lt; w.size() &amp;lt;&amp;lt; &quot;\n&quot;;

    w.clear();
    w.resize(N);

    for(int i=0; i&amp;lt;N; i++) w[f(i)]++;

    int Max = 0;
    for(int i=0; i&amp;lt;N; i++) Max = max(Max, w[i]);

    cout &amp;lt;&amp;lt; Max &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 17387번 : 선분 교차 2&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;기하학, 선분 교차 판정&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 선분의 끝 점의 좌표가 주어질 때, 두 선분의 교차 여부를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 문제와 달리 교차점의 좌표를 구하지 않아도 되므로, 위 문제의 하위 버전임을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 문제의 풀이 코드에서 coor 함수 부분만 지워주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661619623487&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { int x, y; };

bool operator== (s a, s b) {
    if(a.x == b.x &amp;amp;&amp;amp; a.y == b.y) return true;
    else return false;
}
bool operator&amp;gt;= (s a, s b) {
    if(a.x &amp;gt; b.x || (a.x == b.x &amp;amp;&amp;amp; a.y &amp;gt;= b.y)) return true;
    else return false;
}
bool operator&amp;lt;= (s a, s b) {
    if(a.x &amp;lt; b.x || (a.x == b.x &amp;amp;&amp;amp; a.y &amp;lt;= b.y)) return true;
    else return false;
}
bool operator&amp;gt; (s a, s b) {
    if(a.x &amp;gt; b.x || (a.x == b.x &amp;amp;&amp;amp; a.y &amp;gt; b.y)) return true;
    else return false;
}
bool operator&amp;lt; (s a, s b) {
    if(a.x &amp;lt; b.x || (a.x == b.x &amp;amp;&amp;amp; a.y &amp;lt; b.y)) return true;
    else return false;
}

int ccw(s a, s b, s c) {
    int val = a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y);

    if(val == 0) return 0;
    else if(val &amp;gt; 0) return 1;
    else if(val &amp;lt; 0) return -1;
}

void inter(s a, s b, s c, s d) {
    int val1 = ccw(a, b, c) * ccw(a, b, d);
    int val2 = ccw(c, d, a) * ccw(c, d, b);

    if(val1 == 0 &amp;amp;&amp;amp; val2 == 0) {
        if(a &amp;gt; b) swap(a, b);
        if(c &amp;gt; d) swap(c, d);

        if(a &amp;lt;= d &amp;amp;&amp;amp; b &amp;gt;= c) cout &amp;lt;&amp;lt; 1 &amp;lt;&amp;lt; &quot;\n&quot;;
        else cout &amp;lt;&amp;lt; 0 &amp;lt;&amp;lt; &quot;\n&quot;;
    }
    else {
        if(val1 &amp;lt;= 0 &amp;amp;&amp;amp; val2 &amp;lt;= 0) cout &amp;lt;&amp;lt; 1 &amp;lt;&amp;lt; &quot;\n&quot;;
        else cout &amp;lt;&amp;lt; 0 &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    vector&amp;lt;s&amp;gt; p(4);
    for(int i=0; i&amp;lt;4; i++) cin &amp;gt;&amp;gt; p[i].x &amp;gt;&amp;gt; p[i].y;

    cout &amp;lt;&amp;lt; fixed;
    cout.precision(9);

    inter(p[0], p[1], p[2], p[3]);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 1558번 : 그림의 개수&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;기하학, 선분 교차 판정, 분리 집합&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연속된 선분으로 이루어졌고 각 선분의 시작점이 이전 점인 선분의 집합을 폴리라인이라고 할 때, N개의 폴리라인이 주어졌을 때 하나의 점이라도 공유하면 같은 그림이라고 한다면 몇 개의 그림이 존재하는지 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4중 for문으로 모든 폴리라인 쌍의 모든 선분 쌍에 대해 하나라도 교차가 있으면 분리 집합을 이용하여 같은 그룹으로 처리해준 뒤 마지막에 그룹의 개수를 세어주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661685456427&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { int x, y; };

bool operator== (s a, s b) {
    if(a.x == b.x &amp;amp;&amp;amp; a.y == b.y) return true;
    else return false;
}
bool operator&amp;gt;= (s a, s b) {
    if(a.x &amp;gt; b.x || (a.x == b.x &amp;amp;&amp;amp; a.y &amp;gt;= b.y)) return true;
    else return false;
}
bool operator&amp;lt;= (s a, s b) {
    if(a.x &amp;lt; b.x || (a.x == b.x &amp;amp;&amp;amp; a.y &amp;lt;= b.y)) return true;
    else return false;
}
bool operator&amp;gt; (s a, s b) {
    if(a.x &amp;gt; b.x || (a.x == b.x &amp;amp;&amp;amp; a.y &amp;gt; b.y)) return true;
    else return false;
}
bool operator&amp;lt; (s a, s b) {
    if(a.x &amp;lt; b.x || (a.x == b.x &amp;amp;&amp;amp; a.y &amp;lt; b.y)) return true;
    else return false;
}

int ccw(s a, s b, s c) {
    int val = a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y);

    if(val == 0) return 0;
    else if(val &amp;gt; 0) return 1;
    else if(val &amp;lt; 0) return -1;
}

bool cross, overlap;
double cx, cy;

void coor(s a, s b, s c, s d) {
    double X = (a.x * b.y - a.y * b.x) * (c.x - d.x) - (a.x - b.x) * (c.x * d.y - c.y * d.x);
    double Y = (a.x * b.y - a.y * b.x) * (c.y - d.y) - (a.y - b.y) * (c.x * d.y - c.y * d.x);
    double div = (a.x - b.x) * (c.y - d.y) - (a.y - b.y) * (c.x - d.x);

    if(div == 0) {
        if(b == c &amp;amp;&amp;amp; a &amp;lt;= c) cx = b.x, cy = b.y, overlap = false;
        else if(a == d &amp;amp;&amp;amp; c &amp;lt;= a) cx = a.x, cy = a.y, overlap = false;
        else overlap = true;
    }
    else cx = X / div, cy = Y / div, overlap = false;
}

void inter(s a, s b, s c, s d) {
    int val1 = ccw(a, b, c) * ccw(a, b, d);
    int val2 = ccw(c, d, a) * ccw(c, d, b);

    if(val1 == 0 &amp;amp;&amp;amp; val2 == 0) {
        if(a &amp;gt; b) swap(a, b);
        if(c &amp;gt; d) swap(c, d);

        if(a &amp;lt;= d &amp;amp;&amp;amp; b &amp;gt;= c) {
            cross = true;
            coor(a, b, c, d);
        }
        else cross = false;
    }
    else {
        if(val1 &amp;lt;= 0 &amp;amp;&amp;amp; val2 &amp;lt;= 0) {
            cross = true;
            coor(a, b, c, d);
        }
        else cross = false;
    }
}

vector&amp;lt;int&amp;gt; u;

int f(int x) {
    if(x == u[x]) return x;
    else return x = f(u[x]);
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;vector&amp;lt;s&amp;gt;&amp;gt; v(N);
    for(int i=0; i&amp;lt;N; i++) {
        int M; cin &amp;gt;&amp;gt; M;

        while(M--) {
            s tmp; cin &amp;gt;&amp;gt; tmp.x &amp;gt;&amp;gt; tmp.y;

            v[i].push_back(tmp);
        }

        if(v[i].size() == 1) v[i].push_back(v[i].back());
    }

    u.resize(N);
    for(int i=0; i&amp;lt;N; i++) u[i] = i;

    for(int i=0; i&amp;lt;N; i++)
        for(int j=i+1; j&amp;lt;N; j++) {
            bool check = false;

            for(int k=1; k&amp;lt;v[i].size(); k++)
                for(int l=1; l&amp;lt;v[j].size(); l++) {
                    inter(v[i][k-1], v[i][k], v[j][l-1], v[j][l]);

                    if(cross) check = true;
                }

            if(check &amp;amp;&amp;amp; f(i) != f(j)) u[f(i)] = f(j);
        }

    vector&amp;lt;int&amp;gt; w;
    for(int i=0; i&amp;lt;N; i++) w.push_back(f(i));

    sort(w.begin(), w.end());
    w.erase(unique(w.begin(), w.end()), w.end());

    cout &amp;lt;&amp;lt; w.size() &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/알고리즘 공부 내용 정리</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/622</guid>
      <comments>https://restudycafe.tistory.com/622#entry622comment</comments>
      <pubDate>Sun, 28 Aug 2022 01:55:45 +0900</pubDate>
    </item>
    <item>
      <title>2-SAT 알고리즘 응용 문제 풀어보기 220827</title>
      <link>https://restudycafe.tistory.com/621</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 11281번 : 2-SAT - 4&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;SCC, 2-SAT&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2-SAT에 맞는 식이 주어질 때 x1 ~ xN에 참 또는 거짓을 넣어 식 전체가 참이 되도록 만들 수 있는지 판별하고, 만약 가능하다면 식을 참으로 만드는 각 변수 x1 ~ xN의 값으로 가능한 것을 하나 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;식을 참으로 만들 수 있는지 여부의 판별은 2-SAT - 3의 풀이와 동일하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 식을 만족시키는 각 변수의 참/거짓 값을 찾아야하는데, 그리디하게 접근해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;x &amp;rarr; y라는 식이 거짓이 되는 경우는 x = true, y = false인 경우뿐이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;x = false이면 y는 true든 false든 관계없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;식을 최대한 참으로 만들기 위한 최선의 전략은 노드들을 연결했을 때 앞인 것에서부터 값들을 false로 만들어주면 된다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 x = false라면, ~x = true이므로 반대에 해당하는 번호의 노드는 true로 체크해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 이제 다음 문제는 연결 관계가 앞인 것부터 어떻게 접근하냐는 것인데, 이것은 SCC 알고리즘에 원리에 의해 쉽게 구현이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐하면 dfs를 수행할 때 깊이가 깊은 것부터 scc 번호가 매겨졌으므로, scc 그룹의 번호가 큰 것이 위상적으로 앞에 위치하기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 scc 번호를 기준으로 내림차순 정렬을 한 뒤, 앞에서부터 false를 매겨주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661599652940&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj, scc;
vector&amp;lt;int&amp;gt; nnum, cnum;
int ncnt = 0, ccnt = 0;

stack&amp;lt;int&amp;gt; s;
vector&amp;lt;bool&amp;gt; ch;

int dfs(int x) {
    nnum[x] = ++ncnt;
    s.push(x);

    int tmp = nnum[x];

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(nnum[y] == 0) tmp = min(tmp, dfs(y));
        else if(!ch[y]) tmp = min(tmp, nnum[y]);
    }

    if(tmp == nnum[x]) {
        vector&amp;lt;int&amp;gt; v;
        ccnt++;

        while(true) {
            int y = s.top();
            s.pop();

            v.push_back(y);

            ch[y] = true;
            cnum[y] = ccnt;

            if(y == x) break;
        }

        sort(v.begin(), v.end());

        scc.push_back(v);
    }

    return tmp;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    adj.resize(N*2);

    while(M--) {
        int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

        if(a &amp;lt; 0) a = (-a)*2 - 2;
        else a = a*2 - 1;

        if(b &amp;lt; 0) b = (-b)*2 - 2;
        else b = b*2 - 1;

        int na, nb;

        if(a % 2 == 0) na = a + 1;
        else na = a - 1;

        if(b % 2 == 0) nb = b + 1;
        else nb = b - 1;

        adj[na].push_back(b);
        adj[nb].push_back(a);
    }

    nnum.resize(N*2);
    cnum.resize(N*2);
    ch.resize(N*2);

    for(int i=0; i&amp;lt;N*2; i++)
        if(nnum[i] == 0) dfs(i);

    bool check = true;

    for(int i=0; i&amp;lt;N; i++) {
        if(cnum[i*2] == cnum[i*2 + 1]) {
            check = false;
            break;
        }
    }

    if(check) cout &amp;lt;&amp;lt; 1 &amp;lt;&amp;lt; &quot;\n&quot;;
    else {
        cout &amp;lt;&amp;lt; 0 &amp;lt;&amp;lt; &quot;\n&quot;;
        return 0;
    }

    vector&amp;lt;pair&amp;lt;int, int&amp;gt;&amp;gt; p(N*2);
    for(int i=0; i&amp;lt;N*2; i++) p[i] = {cnum[i], i};

    sort(p.begin(), p.end(), greater&amp;lt;pair&amp;lt;int, int&amp;gt;&amp;gt;());

    vector&amp;lt;int&amp;gt; tf(N*2, -1);

    for(int i=0; i&amp;lt;N*2; i++) {
        int x = p[i].second;

        if(tf[x/2] == -1) {
            if(x % 2 == 1) tf[x/2] = 0;
            else tf[x/2] = 1;
        }
    }

    for(int i=0; i&amp;lt;N; i++) cout &amp;lt;&amp;lt; tf[i] &amp;lt;&amp;lt; &quot; &quot;;
    cout &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 이 문제와 동일한 풀이 코드로 &lt;b&gt;백준 BOJ 11278번 : 2-SAT - 2&lt;/b&gt; 문제를 풀이할 수 있다. (범위만 더 작음)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 3648번 : 아이돌&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;SCC, 2-SAT&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N명의 참가자에 대해 M명의 심사위원이 각각 두 명의 참가자에 대해 찬성, 반대를 하는데, 1번 참가자는 반드시 선발하면서 각 심사위원의 평가 중 최소 하나는 반영되도록 선발 멤버를 뽑을 수 있는지의 여부를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나머지는 기본적인 2-SAT 문제와 동일한데, 1번 참가자를 반드시 합격시키는 조건이 포함된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것은 기존의 식에 (x1 &amp;or; x1) 절을 포함시켜서 해결이 가능하다. (그러면 x1이 반드시 참이 되어야하므로)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 그래프를 연결해주어야 하는데, 양쪽 항이 동일하므로 ~x1 &amp;rarr; x1 하나만 이어주면 된다. (아래의 풀이 코드에서는 adj[0].push_back(1);에 해당)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661597832787&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj, scc;
vector&amp;lt;int&amp;gt; nnum, cnum;
int ncnt = 0, ccnt = 0;

stack&amp;lt;int&amp;gt; s;
vector&amp;lt;bool&amp;gt; ch;

int dfs(int x) {
    nnum[x] = ++ncnt;
    s.push(x);

    int tmp = nnum[x];

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(nnum[y] == 0) tmp = min(tmp, dfs(y));
        else if(!ch[y]) tmp = min(tmp, nnum[y]);
    }

    if(tmp == nnum[x]) {
        vector&amp;lt;int&amp;gt; v;
        ccnt++;

        while(true) {
            int y = s.top();
            s.pop();

            v.push_back(y);

            ch[y] = true;
            cnum[y] = ccnt;

            if(y == x) break;
        }

        sort(v.begin(), v.end());

        scc.push_back(v);
    }

    return tmp;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M;

    while(cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M) {
        adj.clear(); adj.resize(N*2);

        while(M--) {
            int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

            if(a &amp;lt; 0) a = (-a)*2 - 2;
            else a = a*2 - 1;

            if(b &amp;lt; 0) b = (-b)*2 - 2;
            else b = b*2 - 1;

            int na, nb;

            if(a % 2 == 0) na = a + 1;
            else na = a - 1;

            if(b % 2 == 0) nb = b + 1;
            else nb = b - 1;

            adj[na].push_back(b);
            adj[nb].push_back(a);
        }

        adj[0].push_back(1);

        nnum.clear(); nnum.resize(N*2);
        cnum.clear(); cnum.resize(N*2);
        ch.clear();   ch.resize(N*2);

        for(int i=0; i&amp;lt;N*2; i++)
            if(nnum[i] == 0) dfs(i);

        bool check = true;

        for(int i=0; i&amp;lt;N; i++) {
            if(cnum[i*2] == cnum[i*2 + 1]) {
                check = false;
                break;
            }
        }

        if(check) cout &amp;lt;&amp;lt; &quot;yes\n&quot;;
        else cout &amp;lt;&amp;lt; &quot;no\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 16915번 : 호텔 관리&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;SCC, 2-SAT&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 방이 각 2개의 스위치에 연결되어 있으며, M개의 스위치에 대해 연결되어 있는 방의 정보가 주어질 때, 스위치를 누르면 연결되어있는 방들의 문이 toggle (열려 있으면 닫히고, 닫혀 있으면 열림) 된다고 한다면 방의 초기 문의 상태가 주어졌을 때 주어진 스위치들만으로 방의 문을 열 수 있는지 묻는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 방이 무조건 2개의 스위치에만 연결되어있다는 것이 포인트이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 연결된 상태를 이용하여 2-SAT 문제로 치환시켜 생각할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 어떤 방이 a번 스위치와 b번 스위치에 연결되어 있다고 할 때, 문이 열려있다면 두 스위치 모두 누르거나 누르지 않아야 하며 (a &amp;rarr; b, ~a &amp;rarr; ~b) 문이 닫혀있다면 둘 중 하나의 스위치만 눌러야 한다. (a &amp;rarr; ~b, ~a &amp;rarr; b)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 그래프 연결을 해주고 SCC를 돌린 뒤 기본적인 2-SAT 알고리즘 풀이대로 풀어주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661612890197&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj, scc;
vector&amp;lt;int&amp;gt; nnum, cnum;
int ncnt = 0, ccnt = 0;

stack&amp;lt;int&amp;gt; s;
vector&amp;lt;bool&amp;gt; ch;

int dfs(int x) {
    nnum[x] = ++ncnt;
    s.push(x);

    int tmp = nnum[x];

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(nnum[y] == 0) tmp = min(tmp, dfs(y));
        else if(!ch[y]) tmp = min(tmp, nnum[y]);
    }

    if(tmp == nnum[x]) {
        vector&amp;lt;int&amp;gt; v;
        ccnt++;

        while(true) {
            int y = s.top();
            s.pop();

            v.push_back(y);

            ch[y] = true;
            cnum[y] = ccnt;

            if(y == x) break;
        }

        sort(v.begin(), v.end());

        scc.push_back(v);
    }

    return tmp;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    vector&amp;lt;int&amp;gt; v(N+1);
    for(int i=1; i&amp;lt;=N; i++) cin &amp;gt;&amp;gt; v[i];

    vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; u(N+1);

    for(int i=1; i&amp;lt;=M; i++) {
        int K; cin &amp;gt;&amp;gt; K;

        while(K--) {
            int x; cin &amp;gt;&amp;gt; x;

            u[x].push_back(i);
        }
    }

    adj.resize(M*2);

    for(int i=1; i&amp;lt;=N; i++) {
        int a = u[i][0]*2 - 1, b = u[i][1]*2 - 1;

        int na = a - 1, nb = b - 1;

        if(v[i] == 0) {
            adj[a].push_back(nb);
            adj[b].push_back(na);
            adj[na].push_back(b);
            adj[nb].push_back(a);
        }
        else {
            adj[a].push_back(b);
            adj[b].push_back(a);
            adj[na].push_back(nb);
            adj[nb].push_back(na);
        }
    }

    nnum.resize(M*2);
    cnum.resize(M*2);
    ch.resize(M*2);

    for(int i=0; i&amp;lt;M*2; i++)
        if(nnum[i] == 0) dfs(i);

    bool check = true;

    for(int i=0; i&amp;lt;M; i++) {
        if(cnum[i*2] == cnum[i*2 + 1]) {
            check = false;
            break;
        }
    }

    if(check) cout &amp;lt;&amp;lt; 1 &amp;lt;&amp;lt; &quot;\n&quot;;
    else cout &amp;lt;&amp;lt; 0 &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 7535번 : A Bug's Life&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;그래프 탐색&lt;/span&gt; (SCC, 2-SAT)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N마리의 벌레가 있고, M개의 상호작용 쌍이 주어질 때, 서로 다른 성별의 벌레들끼리만 상호작용을 한다면 주어진 벌레들 중에서 규칙을 어기는 벌레가 있었는지 검사하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N마리의 성별을 bool 변수로 잡고 true면 수컷, false면 암컷이라고 하면 2-SAT 문제가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;a b가 상호작용을 했다면 a가 수컷이라면 b는 암컷이고, a가 암컷이라면 b는 수컷이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 a &amp;rarr; ~b, b &amp;rarr; ~a, ~a &amp;rarr; b, ~b &amp;rarr; a라는 4개의 명제가 얻어진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 SCC와 2-SAT 알고리즘으로 풀이해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661607227703&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj, scc;
vector&amp;lt;int&amp;gt; nnum, cnum;
int ncnt = 0, ccnt = 0;

stack&amp;lt;int&amp;gt; s;
vector&amp;lt;bool&amp;gt; ch;

int dfs(int x) {
    nnum[x] = ++ncnt;
    s.push(x);

    int tmp = nnum[x];

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(nnum[y] == 0) tmp = min(tmp, dfs(y));
        else if(!ch[y]) tmp = min(tmp, nnum[y]);
    }

    if(tmp == nnum[x]) {
        vector&amp;lt;int&amp;gt; v;
        ccnt++;

        while(true) {
            int y = s.top();
            s.pop();

            v.push_back(y);

            ch[y] = true;
            cnum[y] = ccnt;

            if(y == x) break;
        }

        sort(v.begin(), v.end());

        scc.push_back(v);
    }

    return tmp;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    for(int t=1; t&amp;lt;=T; t++) {
        int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

        adj.clear(); adj.resize(N*2);

        while(M--) {
            int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

            if(a &amp;lt; 0) a = (-a)*2 - 2;
            else a = a*2 - 1;

            if(b &amp;lt; 0) b = (-b)*2 - 2;
            else b = b*2 - 1;

            int na, nb;

            if(a % 2 == 0) na = a + 1;
            else na = a - 1;

            if(b % 2 == 0) nb = b + 1;
            else nb = b - 1;

            adj[a].push_back(nb);
            adj[b].push_back(na);

            adj[na].push_back(b);
            adj[nb].push_back(a);
        }

        nnum.clear(); nnum.resize(N*2);
        cnum.clear(); cnum.resize(N*2);
        ch.clear();   ch.resize(N*2);

        for(int i=0; i&amp;lt;N*2; i++)
            if(nnum[i] == 0) dfs(i);

        bool check = true;

        for(int i=0; i&amp;lt;N; i++) {
            if(cnum[i*2] == cnum[i*2 + 1]) {
                check = false;
                break;
            }
        }

        cout &amp;lt;&amp;lt; &quot;Scenario #&quot; &amp;lt;&amp;lt; t &amp;lt;&amp;lt; &quot;:\n&quot;;

        if(check) cout &amp;lt;&amp;lt; &quot;No suspicious bugs found!\n\n&quot;;
        else cout &amp;lt;&amp;lt; &quot;Suspicious bugs found!\n\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/알고리즘 공부 내용 정리</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/621</guid>
      <comments>https://restudycafe.tistory.com/621#entry621comment</comments>
      <pubDate>Sat, 27 Aug 2022 20:38:36 +0900</pubDate>
    </item>
    <item>
      <title>백준 BOJ 2-SAT 알고리즘, 우선순위 큐 등 풀이 220826</title>
      <link>https://restudycafe.tistory.com/620</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 11280번 : 2-SAT - 3&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;SCC, 2-SAT&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;bool 변수 x1, ... , xn에 대해서 F = (xi &amp;or; xj) &amp;and; (xk &amp;or; xl) &amp;and; ... 와 같은 꼴의 식이 주어질 때, 변수들의 참 거짓을 적절히 설정하여 F의 값이 참이 되게 할 수 있는지 판별하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(a &amp;or; b)와 같은 식이 있을 때 a가 거짓이면 b가 참, b가 거짓이면 a가 참이라는 두 개의 식을 얻을 수 있고 이렇게 2M개의 식을 얻은 뒤 x와 ~x가 모두 참인 식이 하나라도 나오면 불가능, 나머지 경우는 가능이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것은 SCC로 풀이 가능한데, 2N개의 노드에 대해 2M개의 간선을 모두 연결한 그래프를 만든 후 a와 ~a가 같은 scc에 속해있는 경우 불가능임을 판별하면 되기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661517160307&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj, scc;
vector&amp;lt;int&amp;gt; nnum, cnum;
int ncnt = 0, ccnt = 0;

stack&amp;lt;int&amp;gt; s;
vector&amp;lt;bool&amp;gt; ch;

int dfs(int x) {
    nnum[x] = ++ncnt;
    s.push(x);

    int tmp = nnum[x];

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(nnum[y] == 0) tmp = min(tmp, dfs(y));
        else if(!ch[y]) tmp = min(tmp, nnum[y]);
    }

    if(tmp == nnum[x]) {
        vector&amp;lt;int&amp;gt; v;
        ccnt++;

        while(true) {
            int y = s.top();
            s.pop();

            v.push_back(y);

            ch[y] = true;
            cnum[y] = ccnt;

            if(y == x) break;
        }

        sort(v.begin(), v.end());

        scc.push_back(v);
    }

    return tmp;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    adj.resize(N*2);

    while(M--) {
        int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

        if(a &amp;lt; 0) a = (-a)*2 - 2;
        else a = a*2 - 1;

        if(b &amp;lt; 0) b = (-b)*2 - 2;
        else b = b*2 - 1;

        int na, nb;

        if(a % 2 == 0) na = a + 1;
        else na = a - 1;

        if(b % 2 == 0) nb = b + 1;
        else nb = b - 1;

        adj[na].push_back(b);
        adj[nb].push_back(a);
    }

    nnum.resize(N*2);
    cnum.resize(N*2);
    ch.resize(N*2);

    for(int i=0; i&amp;lt;N*2; i++)
        if(nnum[i] == 0) dfs(i);

    for(int i=0; i&amp;lt;N; i++) {
        if(cnum[i*2] == cnum[i*2 + 1]) {
            cout &amp;lt;&amp;lt; 0 &amp;lt;&amp;lt; &quot;\n&quot;;
            return 0;
        }
    }

    cout &amp;lt;&amp;lt; 1 &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;백준 BOJ 1217번 : 하우스 M.D.&lt;/b&gt;, &lt;b&gt;백준 BOJ 2207번 : 가위바위보&lt;/b&gt;, &lt;b&gt;백준 BOJ 3747번 : 완벽한 선거&lt;/b&gt;! 모두 이 문제와 동일한 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;백준 BOJ 11277번 : 2-SAT - 1&lt;/b&gt; 문제는 이 문제보다 범위가 작은 하위 문제로, 동일한 풀이 코드로 풀이할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 18149번 : Length of Bundle Rope&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;우선순위 큐&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 줄의 길이가 주어지고, 길이가 a인 줄과 길이가 b인 줄을 연결하는데 a+b의 비용이 든다면, 모든 줄을 연결하는데 필요한 최소 비용을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;a, b, c 3개의 줄을 연결한다고 생각해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;a와 b를 연결하면 a+b의 비용이 들고, 그 다음 연결된 a, b에 c를 연결하면 a+b+c의 비용이 들어 총 2a+2b+c의 비용이 든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것으로 알 수 있는 사실은 먼저 연결한 줄의 비용이 더 든다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 우선순위 큐로 짧은 줄의 길이가 top으로 오게 한 뒤 2개씩 top에서 꺼내어 합치고 비용을 더해주는 방식으로 문제를 풀이할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661487884249&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    while(T--) {
        int N; cin &amp;gt;&amp;gt; N;

        priority_queue&amp;lt;int, vector&amp;lt;int&amp;gt;, greater&amp;lt;int&amp;gt;&amp;gt; pq;

        while(N--) {
            int x; cin &amp;gt;&amp;gt; x;

            pq.push(x);
        }

        int ans = 0;

        while(true) {
            int x = pq.top();
            pq.pop();

            if(pq.empty()) break;

            int y = pq.top();
            pq.pop();

            ans += x + y;
            pq.push(x + y);
        }

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 6195번 : Fence Repair&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;우선순위 큐&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;길이가 N개 부분 길이의 총합인 fence를 N개의 부분으로 나눌 때, 길이 a+b인 fence를 a, b로 나누는 비용이 a+b라고 한다면 fence를 N개의 조각으로 나누는 최소 비용을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조각을 나누는 것이 아니라 역으로 합쳐가면서 최소 비용을 구한다고 생각해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 a, b 두 조각을 합치는 비용이 a+b로 위의 문제 상황과 같은 상황이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 동일한 코드로 풀이해줄 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661488008062&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    priority_queue&amp;lt;int, vector&amp;lt;int&amp;gt;, greater&amp;lt;int&amp;gt;&amp;gt; pq;

    while(N--) {
        int x; cin &amp;gt;&amp;gt; x;

        pq.push(x);
    }

    int ans = 0;

    while(true) {
        int x = pq.top();
        pq.pop();

        if(pq.empty()) break;

        int y = pq.top();
        pq.pop();

        ans += x + y;
        pq.push(x + y);
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 11679번 : Canvas Painting&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;우선순위 큐&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 구획으로 나누어진 캔버스를 칠하는 비용에 대한 규칙이 주어지고, 모든 구획을 다른 색으로 칠하기 위해 필요한 최소 비용을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;규칙이 다른 문제에 비해서 복잡하게 되어있으나, 결국은 위의 상황들과 똑같이 치환시켜서 생각할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백준 BOJ 18149 문제와 동일한 풀이 코드로 정답 처리를 받을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 13975번 : 파일 합치기 3&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;우선순위 큐&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 파일이 있는데, 두 파일을 합칠 때 두 파일의 크기만큼 비용이 든다고 할 때, 모든 파일을 합치기 위해 필요한 최소 비용을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역시 위의 문제들과 동일한 상황이며, 똑같은 코드로 풀이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 2696번 : 중앙값 구하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;우선순위 큐&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;값이 입력이 하나씩 들어오고, 홀수 번째 수가 입력될 때마다 그 때의 중앙값을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선순위 큐 두 개를 이용하여, 양쪽의 수가 똑같아지도록 유지하면서 큐 두 개에 입력을 받으면 중앙값을 즉시 구할 수 있게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;top에 최댓값이 오도록 하는 pq는 작은 수 절반을 저장하도록 하고, top에 최솟값이 오도록 하는 pq에는 큰 수 절반을 저장하도록 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 top의 값의 크기 관계가 반대가 되었다면 가장 최근에 들어온 값 1개가 문제가 되는 것이므로 top에 있는 값의 위치만 바꾸어주면 우선순위 큐에 들어가서는 알아서 log 시간에 정렬이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661500608171&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    while(T--) {
        int N; cin &amp;gt;&amp;gt; N;

        priority_queue&amp;lt;int&amp;gt; qx;
        priority_queue&amp;lt;int, vector&amp;lt;int&amp;gt;, greater&amp;lt;int&amp;gt;&amp;gt; qn;

        vector&amp;lt;int&amp;gt; v;

        for(int i=0; i&amp;lt;N; i++) {
            int x; cin &amp;gt;&amp;gt; x;

            if(qx.size() == qn.size()) qx.push(x);
            else qn.push(x);

            if(!qx.empty() &amp;amp;&amp;amp; !qn.empty() &amp;amp;&amp;amp; qx.top() &amp;gt; qn.top()) {
                int x = qx.top();
                int y = qn.top();

                qx.pop();
                qn.pop();

                qx.push(y);
                qn.push(x);
            }

            if(i % 2 == 0) v.push_back(qx.top());
        }

        cout &amp;lt;&amp;lt; v.size() &amp;lt;&amp;lt; &quot;\n&quot;;

        for(int i=0; i&amp;lt;v.size(); i++) {
            cout &amp;lt;&amp;lt; v[i] &amp;lt;&amp;lt; &quot; &quot;;

            if(i % 10 == 9) cout &amp;lt;&amp;lt; &quot;\n&quot;;
        }

        cout &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 10166번 : 관중석&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;유클리드 호제법&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1169&quot; data-origin-height=&quot;495&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvwAvG/btrKHZ3ghaV/hQcLwgncN3cxcmVqfkYuEk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvwAvG/btrKHZ3ghaV/hQcLwgncN3cxcmVqfkYuEk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvwAvG/btrKHZ3ghaV/hQcLwgncN3cxcmVqfkYuEk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvwAvG%2FbtrKHZ3ghaV%2FhQcLwgncN3cxcmVqfkYuEk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1169&quot; height=&quot;495&quot; data-origin-width=&quot;1169&quot; data-origin-height=&quot;495&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 반지름이 D인 원 위에 관중석이 일정한 간격으로 D개 있는 원이 D1 ~ D2에 분포되어 있을 때, 앞에 가려지지 않고 중심으로 도달할 수 있는 점들의 개수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각도가 같으면 두 점 중 하나는 가려지게 되므로, 각도에 비례하는 값인 x/D (x = 1 ~ D) 값이 이전에 나온적 있는지를 체크하여 중복을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 i = D1 ~ D2 범위에서, j = 1 ~ i 범위에서 모든 분수를 적어보고 기약분수로 만들어 이전에 나온적 있었는지 체크해보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기약분수를 만드는 과정에서 시간 복잡도를 감소시키기 위해 유클리드 호제법이 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661597449698&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    vector&amp;lt;vector&amp;lt;bool&amp;gt;&amp;gt; v(2001, vector&amp;lt;bool&amp;gt;(2001));
    int ans = 0;

    for(int i=N; i&amp;lt;=M; i++)
        for(int j=1; j&amp;lt;=i; j++) {
            int a = i / __gcd(i, j);
            int b = j / __gcd(i, j);

            if(!v[a][b]) ans++;

            v[a][b] = true;
        }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 11501번 : 주식&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;그리디&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 일이 주어지고 각 날짜의 주식의 가격이 주어질 때, 각 날마다 주식을 1개 사거나 또는 1개 이상 매도할 수 있다고 할 때, N일 후에 취할 수 있는 이득의 최댓값을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뒤에서 앞으로 오면서 지금까지 나온 최댓값에서 현재 가격을 뺀 가격만큼 매일 이득을 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 최댓값을 기록하면서 현재 가격을 뺀 값들을 합쳐주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661597641953&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    while(T--) {
        int N; cin &amp;gt;&amp;gt; N;

        vector&amp;lt;int&amp;gt; v(N);
        for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];

        int Max = 0, ans = 0;

        for(int i=N-1; i&amp;gt;=0; i--) {
            Max = max(Max, v[i]);

            ans += Max - v[i];
        }

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 9253번 : 스페셜 저지&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;문자열&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자열 a, b, c가 주어질 때 a, b의 최대 일치 부분 수열이 c인지 검사하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;a.find(c)는 a에서 c가 나타나는 첫 주소를 반환하고 이를 활용하여 풀이를 구현할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;a에 c가 포함되지 않는 경우 a.find(c) 값은 매우 큰 양수를 가지므로, 이것이 a.length()보다 크거나 같은지 검사하여 c가 문자열에 포함되지 않음을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661597097545&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    string a, b, c; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b &amp;gt;&amp;gt; c;

    if(a.find(c) &amp;gt;= a.length() || b.find(c) &amp;gt;= b.length()) {
        cout &amp;lt;&amp;lt; &quot;NO\n&quot;;
        return 0;
    }

    bool check = true;

    if(a.find(c) &amp;gt; 0 &amp;amp;&amp;amp; b.find(c) &amp;gt; 0 &amp;amp;&amp;amp; a[a.find(c)-1] == b[b.find(c)-1]) check = false;
    if(a.find(c) + c.length() &amp;lt; a.length() &amp;amp;&amp;amp; b.find(c) + c.length() &amp;lt; b.length()
       &amp;amp;&amp;amp; a[a.find(c) + c.length()] == b[b.find(c) + c.length()]) check = false;

    if(check) cout &amp;lt;&amp;lt; &quot;YES\n&quot;;
    else cout &amp;lt;&amp;lt; &quot;NO\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 24957번 : Loop of Chocolate&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 :&lt;span style=&quot;color: #ee2323;&quot;&gt; 기하학, 구현&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3차원 공간 상에서 N개의 구의 좌표가 주어질 때, 구의 총 부피를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 구가 겹치는 경우가 발생한다는 것인데, 반지름이 r인 두 구 사이의 거리가 d(&amp;lt; 2r)일 때 겹치는 공간의 부피는 다음과 같다. (문제에서 알려준다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;212&quot; data-origin-height=&quot;101&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCh6mK/btrKLhhMyoq/J1MVQRbAmsKj93X7ZiPbPk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCh6mK/btrKLhhMyoq/J1MVQRbAmsKj93X7ZiPbPk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCh6mK/btrKLhhMyoq/J1MVQRbAmsKj93X7ZiPbPk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCh6mK%2FbtrKLhhMyoq%2FJ1MVQRbAmsKj93X7ZiPbPk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;212&quot; height=&quot;101&quot; data-origin-width=&quot;212&quot; data-origin-height=&quot;101&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 N개의 구의 부피를 더하고, 거기에서 2중 for문으로 일일이 쌍을 대조해보면서 겹치는 부피들을 빼주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661597067536&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { double x, y, z; };

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    double N, r; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; r;

    vector&amp;lt;s&amp;gt; v(N);
    for(int i=0; i&amp;lt;N; i++)
        cin &amp;gt;&amp;gt; v[i].x &amp;gt;&amp;gt; v[i].y &amp;gt;&amp;gt; v[i].z;

    double ans = N * 4.0 / 3.0 * M_PI * r * r * r;

    for(int i=0; i&amp;lt;N; i++)
        for(int j=i+1; j&amp;lt;N; j++) {
            double d = sqrt(pow(v[i].x - v[j].x, 2) + pow(v[i].y - v[j].y, 2) + pow(v[i].z - v[j].z, 2));

            if(d &amp;gt;= r*2) continue;

            double vol = 2.0 / 3.0 * M_PI * pow(r - d/2, 2) * (2*r + d/2);

            ans -= vol;
        }

    cout &amp;lt;&amp;lt; fixed;
    cout.precision(7);

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>알고리즘/알고리즘 공부 내용 정리</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/620</guid>
      <comments>https://restudycafe.tistory.com/620#entry620comment</comments>
      <pubDate>Fri, 26 Aug 2022 14:06:09 +0900</pubDate>
    </item>
    <item>
      <title>백준 BOJ 우선순위 큐(Priority Queue) 문제 풀이 220825</title>
      <link>https://restudycafe.tistory.com/618</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 13904번 : 과제&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;그리디, 우선순위 큐&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 과제들의 남은 날짜 수와 그 과제의 점수가 주어질 때, 하루에 하나씩 과제를 하여 얻을 수 있는 점수의 최댓값을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 문제들을 남을 일 수를 기준으로 오름차순 정렬해준 뒤, 우선순위 큐에 할 과제들만 남겨보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선순위 큐에 과제를 하나씩 넣고 만약 우선순위 큐의 size가 방금 넣은 날짜 수보다 많다면 같아질 때까지 빼주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;i번째 과제를 넣는 과정을 통해 i일까지 할 과제들을 우선순위 큐에 남긴다고 생각하면, 하루에 한 개씩 과제를 할 수 있으므로 i보다 많은 수의 과제가 들어있으면 안되기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661412172809&quot; class=&quot;arduino&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;pair&amp;lt;int, int&amp;gt;&amp;gt; v(N);

    for(int i=0; i&amp;lt;N; i++)
        cin &amp;gt;&amp;gt; v[i].first &amp;gt;&amp;gt; v[i].second;

    sort(v.begin(), v.end());

    priority_queue&amp;lt;int, vector&amp;lt;int&amp;gt;, greater&amp;lt;int&amp;gt;&amp;gt; pq;

    for(int i=0; i&amp;lt;N; i++) {
        pq.push(v[i].second);

        while(v[i].first &amp;lt; pq.size()) pq.pop();
    }

    int ans = 0;

    while(!pq.empty()) {
        ans += pq.top();
        pq.pop();
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 2109번 : 순회강연&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;그리디, 우선순위 큐&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 강연 목록이 있고, 각 강연은 d일 안에 가서 하면 p의 보상을 받을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하루에 한 개씩 강연을 할 때 최대로 얻을 수 있는 보상의 합을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 문제와 동일하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력부만 v[i].second, v[i].first 순으로 받아주면 동일한 코드로 풀린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661400476276&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;pair&amp;lt;int, int&amp;gt;&amp;gt; v(N);

    for(int i=0; i&amp;lt;N; i++)
        cin &amp;gt;&amp;gt; v[i].second &amp;gt;&amp;gt; v[i].first;

    sort(v.begin(), v.end());

    priority_queue&amp;lt;int, vector&amp;lt;int&amp;gt;, greater&amp;lt;int&amp;gt;&amp;gt; pq;

    for(int i=0; i&amp;lt;N; i++) {
        pq.push(v[i].second);

        while(v[i].first &amp;lt; pq.size()) pq.pop();
    }

    int ans = 0;

    while(!pq.empty()) {
        ans += pq.top();
        pq.pop();
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 9869번 : Milk Scheduling&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;그리디, 우선순위 큐&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;농부가 소들의 젖을 짜는데 그 후보가 N마리이고, 각각 얻을 수 있는 우유의 양과 특정 순서 내에서만 짤 수 있는 번호가 주어질 때, 농부가 얻을 수 있는 우유의 최대 양을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 문제들과 동일한 문제이며, BOJ 2109 풀이와 동일한 소스 코드로 풀린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 1781번 : 컵라면&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;그리디, 우선순위 큐&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 문제들의 데드라인과 그 문제를 풀었을 때 받을 수 있는 컵라면이 주어지고, 단위 시간 당 1개의 문제만 풀이할 수 있을 때 받을 수 있는 컵라면의 최댓값을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 문제들과 동일한 문제이며, BOJ 13904 풀이와 동일한 코드로 풀린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 1374번 : 강의실&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;우선순위 큐&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개 강의의 시작 시간과 끝나는 시간이 주어질 때, 한 강의는 한 강의실에서만 하고 모든 강의를 진행하기 위해서는 최소 몇 개의 강의실이 필요한지 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시작 시간이 증가하는 순으로 오름차순 정렬을 해주고, 우선순위 큐에 강의가 끝나는 시간을 push 해주고 다음 강의와 비교할 때 시작 시간보다 먼저 끝나는 강의들은 pop을 해주는 과정을 반복한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 pq의 size가 최대가 될 때의 크기가 답이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661439137044&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;pair&amp;lt;int, int&amp;gt;&amp;gt; v(N);

    for(int i=0; i&amp;lt;N; i++) {
        int x;

        cin &amp;gt;&amp;gt; x &amp;gt;&amp;gt; v[i].first &amp;gt;&amp;gt; v[i].second;
    }

    sort(v.begin(), v.end());

    priority_queue&amp;lt;int, vector&amp;lt;int&amp;gt;, greater&amp;lt;int&amp;gt;&amp;gt; pq;
    int ans = 0;

    for(int i=0; i&amp;lt;N; i++) {
        while(!pq.empty() &amp;amp;&amp;amp; pq.top() &amp;lt;= v[i].first) pq.pop();

        pq.push(v[i].second);

        ans = max(ans, (int)pq.size());
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 19598번 : 최소 회의실 개수&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;우선순위 큐&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 회의의 시작 시간과 종료 시간이 주어질 때, 필요한 최소 회의실의 개수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 문제와 동일하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회의 번호가 없다는 것만 빼고는 나머지는 동일한 코드로 풀이할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661440021092&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;pair&amp;lt;int, int&amp;gt;&amp;gt; v(N);

    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i].first &amp;gt;&amp;gt; v[i].second;

    sort(v.begin(), v.end());

    priority_queue&amp;lt;int, vector&amp;lt;int&amp;gt;, greater&amp;lt;int&amp;gt;&amp;gt; pq;
    int ans = 0;

    for(int i=0; i&amp;lt;N; i++) {
        while(!pq.empty() &amp;amp;&amp;amp; pq.top() &amp;lt;= v[i].first) pq.pop();

        pq.push(v[i].second);

        ans = max(ans, (int)pq.size());
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 5619번 : 세 번째&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;그리디&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 수가 주어질 때, 두 수를 이어붙여 만든 수들 중 세 번째로 작은 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수를 오름차순으로 정렬하여 i번째로 작은 수를 ai라고 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 a1a4가 a2a1, a3a1 a2a3 등보다 작을 수가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 a4까지는 조합을 해본 뒤 정렬을 해서 답을 구해주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 4C2 x 2 = 12가지 수들을 벡터에 넣고 정렬한 뒤 3번째로 작은 값을 답으로 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래는 우선순위 큐로도 풀 수 있는 문제라고 하지만, 이 풀이가 더 간단해 보여서 이렇게 풀었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661412164556&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;int&amp;gt; v(N);
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];

    sort(v.begin(), v.end());

    vector&amp;lt;int&amp;gt; u;

    string a = to_string(v[0]);
    string b = to_string(v[1]);
    string c = to_string(v[2]);

    u.push_back(stoll(a + b));
    u.push_back(stoll(b + a));
    u.push_back(stoll(b + c));
    u.push_back(stoll(c + b));
    u.push_back(stoll(c + a));
    u.push_back(stoll(a + c));

    if(N &amp;gt;= 4) {
        string d = to_string(v[3]);

        u.push_back(stoll(a + d));
        u.push_back(stoll(b + d));
        u.push_back(stoll(c + d));
        u.push_back(stoll(d + a));
        u.push_back(stoll(d + b));
        u.push_back(stoll(d + c));
    }

    sort(u.begin(), u.end());

    cout &amp;lt;&amp;lt; u[2] &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 13984번 : Contest Score&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;우선순위 큐&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 각 문제의 푸는 시간이 주어질 때, 앞에서 M개의 문제를 보고 시간이 가장 적게 드는 것을 풀고 그 다음 2 ~ M+1번째 문제들에 대해 같은 과정을 반복하고, ... 하여 모든 문제를 푸는데 걸리는 시간 페널티의 합을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선순위 큐를 이용하여 M개의 값을 담고, 그 중 가장 시간이 적은 것을 sum 값에 더하고, 이 sum 값을 ans에 더하는 과정을 반복해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막 N-M개 자료에 대해서는 더 이상 입력을 받지 않고 큐에서 pop 하는 과정만 반복해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661425226688&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    priority_queue&amp;lt;int, vector&amp;lt;int&amp;gt;, greater&amp;lt;int&amp;gt;&amp;gt; pq;

    for(int i=0; i&amp;lt;M; i++) {
        int x; cin &amp;gt;&amp;gt; x;

        pq.push(x);
    }

    int ans = 0, sum = 0;

    for(int i=0; i&amp;lt;N-M; i++) {
        sum += pq.top();
        ans += sum;

        pq.pop();

        int x; cin &amp;gt;&amp;gt; x;
        pq.push(x);
    }

    while(!pq.empty()) {
        sum += pq.top();
        ans += sum;

        pq.pop();
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 23757번 : 아이들과 선물 상자&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;우선순위 큐&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1번부터 N번까지 상자에 들어있는 선물들의 개수가 주어지고, 1번부터 M번 사람까지 원하는 수의 선물이 있을 때, 1번 사람부터 순서대로 나와 남아있는 선물들 중 가장 개수가 많은 것에서 원하는 개수를 가져가고 남은 선물들은 그대로 둘 때, 모든 사람이 선물을 가져갈 수 있는지의 여부를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선순위 큐를 활용하여, 먼저 N개의 수를 넣어 놓고 1번부터 M번 사람까지 순서대로 우선순위 큐의 top에 있는 값과 비교를 하여 원하는 값이 top보다 큰 경우가 있으면 0을 출력해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제를 푸는데 우선순위 큐를 사용하는 것이 수월한 이유는 남은 값을 빼서 구해준 다음 다시 pq에 넣어주기만 하면 되기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661425255090&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    priority_queue&amp;lt;int, vector&amp;lt;int&amp;gt;&amp;gt; pq;

    while(N--) {
        int x; cin &amp;gt;&amp;gt; x;

        pq.push(x);
    }

    bool b = true;

    while(M--) {
        int x; cin &amp;gt;&amp;gt; x;

        if(x &amp;gt; pq.top()) {
            b = false;
            break;
        }

        int tmp = pq.top() - x;

        pq.pop();

        if(tmp &amp;gt; 0) pq.push(tmp);
    }

    if(b) cout &amp;lt;&amp;lt; 1 &amp;lt;&amp;lt; &quot;\n&quot;;
    else cout &amp;lt;&amp;lt; 0 &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 25101번 : Robin Hood&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;우선순위 큐&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N명의 사람의 재산이 있을 때, 도둑이 현재 남은 돈이 가장 많으면서 앞 번호에 있는 사람의 돈을 100원씩 가져간다고 할 때, M번 가져간 후에 남은 사람들의 재산을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 우선순위 큐로 풀이하는 방법을 생각할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 M번의 연산 이후 남은 돈을 순서 그대로 출력해야 한다는 것인데, 이것은 pq 값에 주소까지 넣어서 처리할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 돈을 가진 사람이 여러 명이면 앞에 있는 사람의 돈을 가져가므로, 돈은 내림차순으로하되 주소는 오름차순으로 넣어주어야 한다. (나의 경우에는 주소 값에 그냥 마이너스 부호를 붙여서 주소가 클수록 더 큰 음수가 되어 먼저 나오게 하였다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 pq에서 하나씩 값을 뽑으면서 100을 빼는 연산을 하되, 더 이상 뺄 수 없는 경우는 bool 변수에 기록을 해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661425814975&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    priority_queue&amp;lt;pair&amp;lt;int, int&amp;gt;, vector&amp;lt;pair&amp;lt;int, int&amp;gt;&amp;gt;&amp;gt; pq;
    vector&amp;lt;int&amp;gt; v(N);

    for(int i=0; i&amp;lt;N; i++) {
        cin &amp;gt;&amp;gt; v[i];

        pq.push({v[i], -i});
    }

    bool b = true;

    while(M--) {
        if(pq.top().first &amp;lt;= 100) {
            b = false;
            break;
        }

        int x = pq.top().first;
        int y = -pq.top().second;

        pq.pop();

        v[y] -= 100;

        pq.push({x - 100, -y});
    }

    if(b) {
        for(int i=0; i&amp;lt;N; i++) cout &amp;lt;&amp;lt; v[i] &amp;lt;&amp;lt; &quot; &quot;;
        cout &amp;lt;&amp;lt; &quot;\n&quot;;
    }
    else cout &amp;lt;&amp;lt; &quot;impossible\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/알고리즘 공부 내용 정리</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/618</guid>
      <comments>https://restudycafe.tistory.com/618#entry618comment</comments>
      <pubDate>Thu, 25 Aug 2022 13:05:42 +0900</pubDate>
    </item>
    <item>
      <title>백준 BOJ 안 푼 문제들 중에서 쉬운 문제들 아무거나 220824</title>
      <link>https://restudycafe.tistory.com/617</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 1477번 : 휴게소 세우기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;이분 탐색&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;길이가 K인 도로 위에 N개의 휴게소가 있고, 여기에 M개의 휴게소를 더 지어 휴게소 간 거리의 최댓값이 최소가 되도록 할 때, 그 최솟값을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이분 탐색을 이용하여 풀이할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;답을 m으로 두고 l ~ r 범위 내에서 이분 탐색을 하면서 휴게소 간의 거리를 m으로 두고 휴게소를 설치했을 때 휴게소가 M개 이하로 설치되었는지 확인하면서 값을 갱신해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주의할 점은 두 휴게소 사이의 거리가 x라면, 휴게소는 max(x-1, 0) / m개 설치된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐하면, 예를 들어서 생각해보면 휴게소 사이의 거리가 100인데 거리 50으로 휴게소를 설치한다고 하여 휴게소가 2개 설치되지는 않기 때문이다. (0, 50, 100에 위치에 휴게소가 있으면 되므로 1개만 설치하면 된다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비슷한 방식으로 거리 101의 도로에 휴게소를 50 간격으로 설치할 때는 2개가 설치되므로, 식을 (x-1) / m으로 두어야 함을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661338553356&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M, K; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M &amp;gt;&amp;gt; K;

    vector&amp;lt;int&amp;gt; v(N);
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];

    v.push_back(0);
    v.push_back(K);

    sort(v.begin(), v.end());

    vector&amp;lt;int&amp;gt; u;
    for(int i=1; i&amp;lt;v.size(); i++) u.push_back(max(v[i]-v[i-1]-1, (int)0));

    int ans = INT_MAX, l = 1, r = K;

    while(l &amp;lt;= r) {
        int m = (l + r) / 2;

        int sum = 0;
        for(int i=0; i&amp;lt;u.size(); i++) sum += u[i] / m;

        if(sum &amp;lt;= M) {
            ans = min(ans, m);

            r = m - 1;
        }
        else l = m + 1;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 4232번 : Conformity&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;구현, 해시를 사용한 집합과 맵&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 5개 숫자의 조합이 주어질 때, 이 조합들 중 가장 빈도가 높은 것의 개수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;map&amp;lt;vector&amp;lt;int&amp;gt;, int&amp;gt;을 이용하여 각 조합의 수를 map에 기록하고 (물론 정렬 후 추가해주어야 한다.) 다시 모든 조합에 대해 map의 값을 확인해보면서 최대인 것의 개수를 count 해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661313912051&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    while(true) {
        int N; cin &amp;gt;&amp;gt; N;
        if(N == 0) break;

        map&amp;lt;vector&amp;lt;int&amp;gt;, int&amp;gt; m;
        vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; v(N, vector&amp;lt;int&amp;gt;(5));

        for(int i=0; i&amp;lt;N; i++) {
            for(int j=0; j&amp;lt;5; j++) cin &amp;gt;&amp;gt; v[i][j];

            sort(v[i].begin(), v[i].end());

            m[v[i]]++;
        }

        int Max = 0;

        for(int i=0; i&amp;lt;N; i++)
            Max = max(Max, m[v[i]]);

        int ans = 0;

        for(int i=0; i&amp;lt;N; i++)
            if(m[v[i]] == Max) ans++;

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 10489번 : Even Up Solitaire&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;스택&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 수열이 주어질 때, 인접한 두 수의 합이 짝수면 제거할 수 있다고 할 때 남길 수 있는 수의 최소 개수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;stack을 이용하여 수를 하나씩 입력받으면서, 현재 stack의 top에 있는 수와 새로 들어온 수의 합이 짝수면 두 수를 제거해주고, 아니면 그대로 push 해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661315021930&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    stack&amp;lt;int&amp;gt; s;

    while(N--) {
        int x; cin &amp;gt;&amp;gt; x;

        if(!s.empty() &amp;amp;&amp;amp; (s.top() + x) % 2 == 0) s.pop();
        else s.push(x);
    }

    cout &amp;lt;&amp;lt; s.size() &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 14402번 : 야근&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;해시를 사용한 집합과 맵&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하루동안의 출퇴근 기록이 주어지고, 출근은 +, 퇴근은 -일 때 출근 없이 퇴근만 찍히거나 퇴근 없이 출근만 찍혀있는 경우를 야근이라고 할 때, 야근하는 사람의 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 입력이 &quot;이름 기호&quot; 순으로 주어지므로, string을 기록할 map이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이 map에 대응되는 int 값을 증감시키면 되는데, 값이 0인데 -가 찍히는 경우와 입력이 끝났는데 남아있는 + 값은 전부 야근에 해당되므로 답에 합해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661330191594&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    unordered_map&amp;lt;string, int&amp;gt; m;
    set&amp;lt;string&amp;gt; s;
    int ans = 0;

    while(N--) {
        string str; cin &amp;gt;&amp;gt; str;
        char c; cin &amp;gt;&amp;gt; c;

        if(c == '+') m[str]++;
        else {
            if(m[str] == 0) ans++;
            else m[str]--;
        }

        if(s.count(str) == 0) s.insert(str);
    }

    for(auto i : s) ans += m[i];

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 10657번 : Cow Jog&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;구현&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1차원 좌표 상에서 좌표의 오름차순으로 소의 위치와 오른쪽으로 이동하는 속도가 주어질 때, 두 소가 만나면 추월하지 못하고 같이 이동해야 한다면 최종적으로 소는 몇 그룹으로 묶일지 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더 오른쪽에 있는 소가 더 느릴 경우 두 소는 같은 그룹이 되므로, 맨 오른쪽에서 시작하여 최솟값을 가지는 소가 나올 때마다 그 소가 하나의 그룹을 만든다고 생각하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661281108753&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;int&amp;gt; v(N);
    for(int i=0; i&amp;lt;N; i++) {
        int x; cin &amp;gt;&amp;gt; x &amp;gt;&amp;gt; v[i];
    }

    int Min = INT_MAX, ans = 0;

    for(int i=N-1; i&amp;gt;=0; i--) {
        if(v[i] &amp;lt;= Min) {
            Min = v[i];
            ans++;
        }
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 6296번 : Crazy Search&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt; Silver V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;해시를 사용한 집합과 맵&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용된 문자의 종류가 M인 문자열이 주어질 때, 모든 길이가 N인 부분 수열의 종류를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;unordered_map을 사용하여 쉽게 해결이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;substr 함수는 꽤 느리게 동작하지만, 이 문제에서는 시간 초과 없이 해결이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661282588182&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    string str; cin &amp;gt;&amp;gt; str;

    unordered_map&amp;lt;string, bool&amp;gt; m;
    int ans = 0;

    for(int i=0; i&amp;lt;str.length()-N+1; i++) {
        string tmp = str.substr(i, N);

        if(!m[tmp]) ans++;

        m[tmp] = true;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 19817번 : Company Merging&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;우선순위 큐&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 회사를 합병할 때, 두 회사의 최고 임금의 격차만큼 최고 임금이 적은 기업의 모든 직원에게 추가 급여를 준다고 할 때, N개의 회사를 합병하는 데 필요한 최소 비용을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;합병을 처음에 하나 나중에 하나 결국 최대 비용을 가진 사람을 기준으로 비용이 증가하므로, 합병 순서는 관계 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개 회사 중 최대 급여를 받는 사람의 급여에서 어떤 기업의 최대 급여를 받는 사람의 급여의 격차에 그 회사의 사람 수를 곱한 값들의 합이 답이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 우선순위 큐를 N개 선언하고, 이들의 최댓값들을 미리 정렬해둔 뒤 답을 쉽게 구할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자세한 구현은 코드를 참고하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661283093174&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;priority_queue&amp;lt;int&amp;gt;&amp;gt; pq(N);
    int Max = 0;

    for(int i=0; i&amp;lt;N; i++) {
        int M; cin &amp;gt;&amp;gt; M;

        while(M--) {
            int x; cin &amp;gt;&amp;gt; x;

            pq[i].push(x);

            Max = max(Max, x);
        }
    }

    int ans = 0;

    for(int i=0; i&amp;lt;N; i++)
        ans += (Max - pq[i].top()) * pq[i].size();

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 10689번 : Hamza&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;해시를 사용한 집합과 맵&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 수가 주어질 때, 각 번호는 문제의 유형을 나타내고, 문제는 무조건 앞에서부터 푼다고 할 때 모든 유형의 문제를 풀기 위해서는 몇 문제를 풀어야 하는지 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제의 목록에는 모든 문제의 유형이 포함되어있다는 보장이 있으므로, 새로운 유형이 마지막으로 나온 지점까지가 답이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 map을 이용하여 번호가 이전에 나온적 있는지의 여부를 기록해주고, 나온 적 없는 번호가 있다면 답을 현재 위치로 갱신해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661302412535&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    for(int t=1; t&amp;lt;=T; t++) {
        int N; cin &amp;gt;&amp;gt; N;

        unordered_map&amp;lt;int, bool&amp;gt; m;
        int ans = 0;

        for(int i=0; i&amp;lt;N; i++) {
            int x; cin &amp;gt;&amp;gt; x;

            if(!m[x]) ans = i+1;

            m[x] = true;
        }

        cout &amp;lt;&amp;lt; &quot;Case &quot; &amp;lt;&amp;lt; t &amp;lt;&amp;lt; &quot;: &quot; &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 1331번 : 나이트 투어&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;구현&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주어진 36개의 칸의 목록이 6x6 나이트투어, 즉 체스 나이트가 모든 칸을 경유한 뒤 다시 원래대로 돌아올 수 있는 경로인지를 검사하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;검사해야 하는 것은 다음의 세 가지이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 주어진 칸들 중에서 중복이 없는가 (= 모든 칸을 방문했는가)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 인접한 칸들 사이의 격차가 x는 2만큼, y는 1만큼 또는 x는 1만큼, y는 2만큼 나는가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 마지막 칸에서 첫 번째 칸으로 이동이 가능한가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 세 가지를 구현해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자세한 구현은 코드를 참고하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661302498820&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    vector&amp;lt;string&amp;gt; str(36);

    for(int i=0; i&amp;lt;36; i++) cin &amp;gt;&amp;gt; str[i];

    bool check = true;

    for(int i=0; i&amp;lt;36; i++) {
        int x = str[i][0] - str[(i+1) % 36][0];
        int y = str[i][1] - str[(i+1) % 36][1];

        if(!((abs(x) == 1 &amp;amp;&amp;amp; abs(y) == 2) || (abs(x) == 2 &amp;amp;&amp;amp; abs(y) == 1))) check = false;
    }

    for(int i=0; i&amp;lt;36; i++)
        for(int j=i+1; j&amp;lt;36; j++)
            if(str[i] == str[j]) check = false;

    if(check) cout &amp;lt;&amp;lt; &quot;Valid\n&quot;;
    else cout &amp;lt;&amp;lt; &quot;Invalid\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 1417번 : 국회의원 선거&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;우선순위 큐&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N명의 후보들의 득표 수가 주어질 때, 1번 후보가 단독 1위를 하기 위해서 다른 후보들의 표에서 매수해와야 하는 사람의 최소 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 순위 큐를 이용하여 2~N번 후보의 득표 수를 저장하고, 가장 많은 득표를 한 사람의 표를 1개씩 매수해오면서 1등이 언제 되는지 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661311995754&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    int cur; cin &amp;gt;&amp;gt; cur;

    priority_queue&amp;lt;int&amp;gt; pq;

    for(int i=0; i&amp;lt;N-1; i++) {
        int x; cin &amp;gt;&amp;gt; x;

        pq.push(x);
    }

    if(N == 1) {
        cout &amp;lt;&amp;lt; 0 &amp;lt;&amp;lt; &quot;\n&quot;;
        return 0;
    }

    int ans = 0;

    while(true) {
        if(cur &amp;gt; pq.top()) break;

        int x = pq.top();
        pq.pop();
        pq.push(x-1);

        cur++;
        ans++;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 4649번 : Tanning Salon&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;구현&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 침대가 있는 salon에 문자열로 각 손님의 방문과 떠나는 순서가 주어졌을 때, tanning을 하지 못하고 떠난 손님의 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제에서 tanning을 하지 못한 손님은 반드시 tanning 중인 다른 손님보다 먼저 떠난다고 하였으므로, 매 방문마다 bool 변수가 check 된 것의 개수를 count 해주어 그것이 N보다 큰지 작은지를 파악해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661312680776&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    while(true) {
        int N; cin &amp;gt;&amp;gt; N;
        if(N == 0) break;

        string str; cin &amp;gt;&amp;gt; str;

        vector&amp;lt;bool&amp;gt; v(26);
        int ans = 0;

        for(int i=0; i&amp;lt;str.length(); i++) {
            int cnt = 0;

            for(int i=0; i&amp;lt;26; i++)
                if(v[i]) cnt++;

            int x = str[i] - 'A';

            if(!v[x]) {
                if(cnt &amp;gt;= N) ans++;

                v[x] = true;
            }
            else v[x] = false;
        }

        if(ans == 0) cout &amp;lt;&amp;lt; &quot;All customers tanned successfully.\n&quot;;
        else cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot; customer(s) walked away.\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 4675번 : Word Amalgamation&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;해시를 사용한 집합과 맵, 트리를 사용한 집합과 맵&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사전에 있는 단어들의 목록이 주어지고, 그 다음 철자 순서가 섞인 단어들이 주어질 때, 섞인 단어들의 철자를 바꾸어 만들 수 있는 사전의 단어들의 목록을 사전 순으로 출력하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 사전에 있는 단어들을 문자 각각을 정렬을 한 상태로 (ex : apple &amp;rarr; aelpp) 해당 문자열과 연결된 set에 원래 단어를 저장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 순서가 섞인 단어가 입력되면, 이 역시 정렬한 뒤 map에 저장되어 있는지 체크하고, 저장되어 있다면 해당 map과 연결된 set에서 값들을 찾아와 출력해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;set은 단어들이 정렬된 상태로 저장되므로, set의 모든 원소들을 출력해주기만 하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661309570742&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    map&amp;lt;string, set&amp;lt;string&amp;gt;&amp;gt; m;

    while(true) {
        string str; cin &amp;gt;&amp;gt; str;
        if(str == &quot;XXXXXX&quot;) break;

        string tmp = str;

        sort(tmp.begin(), tmp.end());

        m[tmp].insert(str);
    }

    while(true) {
        string str; cin &amp;gt;&amp;gt; str;
        if(str == &quot;XXXXXX&quot;) break;

        sort(str.begin(), str.end());

        if(m[str].empty()) cout &amp;lt;&amp;lt; &quot;NOT A VALID WORD\n&quot;;
        else {
            for(auto i : m[str]) cout &amp;lt;&amp;lt; i &amp;lt;&amp;lt; &quot;\n&quot;;
        }

        cout &amp;lt;&amp;lt; &quot;******\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 16466번 : 콘서트&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;해시를 사용한 집합과 맵&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 수가 주어질 때, 주어진 수들 중 나타나지 않는 가장 작은 자연수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;map을 이용하여 map에 나온 숫자들을 모두 기록하고, 1부터 확인하면서 map에 없는 최초의 값을 답으로 얻어주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661309750800&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    unordered_map&amp;lt;int, bool&amp;gt; m;

    while(N--) {
        int x; cin &amp;gt;&amp;gt; x;

        m[x] = true;
    }

    for(int i=1; ; i++) {
        if(!m[i]) {
            cout &amp;lt;&amp;lt; i &amp;lt;&amp;lt; &quot;\n&quot;;
            break;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/알고리즘 공부 내용 정리</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/617</guid>
      <comments>https://restudycafe.tistory.com/617#entry617comment</comments>
      <pubDate>Wed, 24 Aug 2022 04:31:37 +0900</pubDate>
    </item>
    <item>
      <title>강한 결합 요소(SCC) 알고리즘 solution들 정리 220823</title>
      <link>https://restudycafe.tistory.com/616</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 2150번 : Strongly Connected Component&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;강한 결합 요소 (SCC)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방향 그래프가 주어질 때, 이들을 SCC로 나누어 출력하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 말하는 &lt;b&gt;SCC(Strongly Connected Component)&lt;/b&gt;란, &lt;u&gt;한 Component 내의 어떤 두 점 사이에도 이동이 가능한 요소&lt;/u&gt;를 말한다. (SCC를 나눌 때는 당연히 한 Component의 크기가 최대가 되도록 나누어야 한다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래프를 입력받고 adj 벡터에 간선들을 저장해주는 부분은 기본적이므로 설명을 생략한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 DFS 방식으로 노드들을 탐색하며, 노드 번호를 방문하는 순서대로 오름차순으로 매긴다. (nnum 벡터에 저장)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 번호를 먼저 매기는 것이긴 하지만 아무튼 &lt;span style=&quot;color: #ee2323;&quot;&gt;번호가 작은 것부터 번호가 큰 순서대로 노드들을 방문&lt;/span&gt;하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;재귀적으로 노드들을 탐색하는데, 1. &lt;span style=&quot;color: #ee2323;&quot;&gt;아직 방문하지 않은 노드&lt;/span&gt;, 2. &lt;span style=&quot;color: #ee2323;&quot;&gt;방문은 했으나 아직 scc로 선택되지 않은 (!ch[y]) 노드&lt;/span&gt;들 중 번호가 가장 작은 것이 자기 자신일 경우, 이 노드들은 순환을 통해 현재 노드로는 되돌아올 수 있으나 자기 자신보다 더 작은 번호의 노드로는 더 이상 거슬러 올라가지 못한다는 뜻이므로 &lt;b&gt;SCC&lt;/b&gt;임을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 이 노드들을 모두 선택(ch[y] = true) 해주고 임시 벡터에 저장하여 2차원 벡터인 scc 벡터에 push_back 해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 scc 벡터를 정렬하여 답을 출력해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(여담으로 아래 코드에서 cnum(component number), ccnt(component count) 값은 이 문제에서는 필요 없으나, 다른 SCC 문제를 풀 때 유용하다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661233912011&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj, scc;
vector&amp;lt;int&amp;gt; nnum, cnum;
int ncnt = 0, ccnt = 0;

stack&amp;lt;int&amp;gt; s;
vector&amp;lt;bool&amp;gt; ch;

int dfs(int x) {
    nnum[x] = ++ncnt;
    s.push(x);

    int tmp = nnum[x];

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(nnum[y] == 0) tmp = min(tmp, dfs(y));
        else if(!ch[y]) tmp = min(tmp, nnum[y]);
    }

    if(tmp == nnum[x]) {
        vector&amp;lt;int&amp;gt; v;
        ccnt++;

        while(true) {
            int y = s.top();
            s.pop();

            v.push_back(y);

            ch[y] = true;
            cnum[y] = ccnt;

            if(y == x) break;
        }

        sort(v.begin(), v.end());

        scc.push_back(v);
    }

    return tmp;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    adj.resize(N+1);

    while(M--) {
        int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

        adj[a].push_back(b);
    }

    nnum.resize(N+1);
    cnum.resize(N+1);
    ch.resize(N+1);

    for(int i=1; i&amp;lt;=N; i++)
        if(nnum[i] == 0) dfs(i);

    sort(scc.begin(), scc.end());

    cout &amp;lt;&amp;lt; scc.size() &amp;lt;&amp;lt; &quot;\n&quot;;

    for(int i=0; i&amp;lt;scc.size(); i++) {
        for(int j=0; j&amp;lt;scc[i].size(); j++) cout &amp;lt;&amp;lt; scc[i][j] &amp;lt;&amp;lt; &quot; &quot;;
        cout &amp;lt;&amp;lt; -1 &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 4196번 : 도미노&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;강한 결합 요소 (SCC)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 도미노가 M개의 연결 관계에 의해 연결되어 있을 때, 모든 도미노를 넘어뜨리기 위해 쓰러뜨려야 하는 최소 도미노의 개수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 scc인 도미노는 어떤 것을 넘어뜨려도 scc 내의 도미노들은 모두 넘어지게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, scc 내의 관계는 신경 쓸 필요 없고 scc와 scc 사이의 연결 관계에 대해 생각해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 scc에서 현재 scc로 들어오는 간선이 있는 경우 다른 scc를 먼저 선택하면 현재 scc로의 이동이 가능하므로 모두 넘어뜨릴 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 scc들 중에서 들어오는 간선이 없는 scc의 개수를 세어주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 구현하기 위해서는, 모든 간선들을 다시 체크해보면서 &lt;span style=&quot;color: #ee2323;&quot;&gt;간선이 서로 다른 두 scc에 속한 노드 사이를 연결할 때, 해당 간선이 가리키는 scc 번호의 ind 값을 1 추가&lt;/span&gt;해주고 최종 ind 값이 0인 scc들의 개수를 세어주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661233919406&quot; class=&quot;arduino&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj, scc;
vector&amp;lt;int&amp;gt; nnum, cnum;
int ncnt = 0, ccnt = 0;

stack&amp;lt;int&amp;gt; s;
vector&amp;lt;bool&amp;gt; ch;

int dfs(int x) {
    nnum[x] = ++ncnt;
    s.push(x);

    int tmp = nnum[x];

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(nnum[y] == 0) tmp = min(tmp, dfs(y));
        else if(!ch[y]) tmp = min(tmp, nnum[y]);
    }

    if(tmp == nnum[x]) {
        vector&amp;lt;int&amp;gt; v;
        ccnt++;

        while(true) {
            int y = s.top();
            s.pop();

            v.push_back(y);

            ch[y] = true;
            cnum[y] = ccnt;

            if(y == x) break;
        }

        sort(v.begin(), v.end());

        scc.push_back(v);
    }

    return tmp;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    while(T--) {
        int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

        adj.clear();
        adj.resize(N+1);

        while(M--) {
            int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

            adj[a].push_back(b);
        }

        nnum.clear();   nnum.resize(N+1);
        cnum.clear();   cnum.resize(N+1);
        ch.clear();     ch.resize(N+1);

        scc.clear();
        ncnt = ccnt = 0;

        for(int i=1; i&amp;lt;=N; i++)
            if(nnum[i] == 0) dfs(i);

        sort(scc.begin(), scc.end());

        vector&amp;lt;int&amp;gt; ind(N+1);

        for(int i=1; i&amp;lt;=N; i++)
            for(int j=0; j&amp;lt;adj[i].size(); j++) {
                int x = adj[i][j];

                if(cnum[i] != cnum[x]) ind[cnum[x]]++;
            }

        int ans = 0;
        for(int i=1; i&amp;lt;=ccnt; i++)
            if(ind[i] == 0) ans++;

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 24131번 : 宣伝&amp;nbsp;(Advertisement)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;강한 결합 요소 (SCC)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N명의 사람이 있고, M개의 쌍에 대해 a번 사람이 b번 사람의 연락처를 알고 있다고 할 때, 정보를 처음 전달했을 때 연락처들을 통해 모든 사람에게 정보가 전달될 수 있게 하기 위해 처음에 정보를 전달해야 하는 최소 사람 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 도미노 문제와 같은 논리가 적용될 수 있음을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 테스트케이스 부분의 구현만 제외하면 나머지는 동일한 풀이로 풀 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661224137055&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj, scc;
vector&amp;lt;int&amp;gt; nnum, cnum;
int ncnt = 0, ccnt = 0;

stack&amp;lt;int&amp;gt; s;
vector&amp;lt;bool&amp;gt; ch;

int dfs(int x) {
    nnum[x] = ++ncnt;
    s.push(x);

    int tmp = nnum[x];

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(nnum[y] == 0) tmp = min(tmp, dfs(y));
        else if(!ch[y]) tmp = min(tmp, nnum[y]);
    }

    if(tmp == nnum[x]) {
        vector&amp;lt;int&amp;gt; v;
        ccnt++;

        while(true) {
            int y = s.top();
            s.pop();

            v.push_back(y);

            ch[y] = true;
            cnum[y] = ccnt;

            if(y == x) break;
        }

        sort(v.begin(), v.end());

        scc.push_back(v);
    }

    return tmp;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    adj.resize(N+1);

    while(M--) {
        int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

        adj[a].push_back(b);
    }

    nnum.resize(N+1);
    cnum.resize(N+1);
    ch.resize(N+1);

    for(int i=1; i&amp;lt;=N; i++)
        if(nnum[i] == 0) dfs(i);

    sort(scc.begin(), scc.end());

    vector&amp;lt;int&amp;gt; ind(N+1);

    for(int i=1; i&amp;lt;=N; i++)
        for(int j=0; j&amp;lt;adj[i].size(); j++) {
            int x = adj[i][j];

            if(cnum[i] != cnum[x]) ind[cnum[x]]++;
        }

    int ans = 0;
    for(int i=1; i&amp;lt;=ccnt; i++)
        if(ind[i] == 0) ans++;

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 13232번 : Domain clusters&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;강한 결합 요소 (SCC)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 도메인들의 연결 관계가 주어질 때, 서로 이동이 가능한 가장 큰 도메인 집합의 크기를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 큰 scc의 크기를 구하라는 것과 동치이므로, scc들을 구해주고 그들 중 가장 scc[i].size()가 큰 것을 답으로 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661233939275&quot; class=&quot;arduino&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj, scc;
vector&amp;lt;int&amp;gt; nnum, cnum;
int ncnt = 0, ccnt = 0;

stack&amp;lt;int&amp;gt; s;
vector&amp;lt;bool&amp;gt; ch;

int dfs(int x) {
    nnum[x] = ++ncnt;
    s.push(x);

    int tmp = nnum[x];

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(nnum[y] == 0) tmp = min(tmp, dfs(y));
        else if(!ch[y]) tmp = min(tmp, nnum[y]);
    }

    if(tmp == nnum[x]) {
        vector&amp;lt;int&amp;gt; v;
        ccnt++;

        while(true) {
            int y = s.top();
            s.pop();

            v.push_back(y);

            ch[y] = true;
            cnum[y] = ccnt;

            if(y == x) break;
        }

        sort(v.begin(), v.end());

        scc.push_back(v);
    }

    return tmp;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    adj.resize(N+1);

    while(M--) {
        int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

        adj[a].push_back(b);
    }

    nnum.resize(N+1);
    cnum.resize(N+1);
    ch.resize(N+1);

    for(int i=1; i&amp;lt;=N; i++)
        if(nnum[i] == 0) dfs(i);

    sort(scc.begin(), scc.end());

    int ans = 0;

    for(int i=0; i&amp;lt;scc.size(); i++)
        ans = max(ans, (int)scc[i].size());

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 1506번 : 경찰서&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;강한 결합 요소 (SCC)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 도시에 경찰서를 세우는 비용이 주어지고, 도시 사이의 단방향 도로들이 주어질 때, 서로 연결된 도시(순환이 가능해야함)들 사이에서는 한 개 이상의 경찰서가 있어야한다고 할 때 이러한 조건을 만족하기 위한 최소 경찰서 설치 비용을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 SCC 내에서는 하나의 경찰서만 있으면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 SCC 알고리즘을 돌려준 이후 각 SCC들에 대해 비용이 가장 작은 노드의 비용을 합해서 답으로 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661233944214&quot; class=&quot;arduino&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj, scc;
vector&amp;lt;int&amp;gt; nnum, cnum;
int ncnt = 0, ccnt = 0;

stack&amp;lt;int&amp;gt; s;
vector&amp;lt;bool&amp;gt; ch;

int dfs(int x) {
    nnum[x] = ++ncnt;
    s.push(x);

    int tmp = nnum[x];

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(nnum[y] == 0) tmp = min(tmp, dfs(y));
        else if(!ch[y]) tmp = min(tmp, nnum[y]);
    }

    if(tmp == nnum[x]) {
        vector&amp;lt;int&amp;gt; v;
        ccnt++;

        while(true) {
            int y = s.top();
            s.pop();

            v.push_back(y);

            ch[y] = true;
            cnum[y] = ccnt;

            if(y == x) break;
        }

        sort(v.begin(), v.end());

        scc.push_back(v);
    }

    return tmp;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;int&amp;gt; v(N+1);
    for(int i=1; i&amp;lt;=N; i++) cin &amp;gt;&amp;gt; v[i];

    adj.resize(N+1);

    for(int i=1; i&amp;lt;=N; i++)
        for(int j=1; j&amp;lt;=N; j++) {
            char c; cin &amp;gt;&amp;gt; c;

            if(c == '1') adj[i].push_back(j);
        }

    nnum.resize(N+1);
    cnum.resize(N+1);
    ch.resize(N+1);

    for(int i=1; i&amp;lt;=N; i++)
        if(nnum[i] == 0) dfs(i);

    sort(scc.begin(), scc.end());

    int ans = 0;

    for(int i=0; i&amp;lt;scc.size(); i++) {
        int Min = INT_MAX;

        for(int j=0; j&amp;lt;scc[i].size(); j++)
            Min = min(Min, v[scc[i][j]]);

        ans += Min;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 3977번 : 축구 전술&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;강한 결합 요소 (SCC)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 노드와 M개의 단방향 간선이 주어질 때, 하나의 노드를 선택하여 모든 노드에 도달할 수 있게 할 때, 가능한 노드의 번호가 있으면 오름차순으로 모두 출력하고, 그렇지 않은 경우 Confused를 출력하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 도미노 문제 아이디어의 연장으로 풀이할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;indegree가 0인 scc는 다른 scc에서 올 수 없으므로 시작점으로 반드시 선택해주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 만약 indegree가 0인 scc가 2개 이상이면 한 노드에서 모든 노드에 도달하는 것이 불가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러므로 이 경우에는 Confused를 출력해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 indegree가 0인 scc가 1개인 경우 해당 scc의 어떤 원소에서 시작하여도 모든 노드에 도달할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 해당 노드들을 오름차순으로 모두 출력해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여담으로 indegree가 0인 scc가 없는 경우는 존재하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;귀류법으로 만약 그러한 indegree가 존재한다고 가정할 경우, 이는 사이클이므로 scc 알고리즘에 의해 이미 더 큰 scc에&amp;nbsp; 소속되어있어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 indegree가 0인 scc가 1개이거나 그보다 많은 경우로만 나누어 생각해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661233951062&quot; class=&quot;arduino&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj, scc;
vector&amp;lt;int&amp;gt; nnum, cnum;
int ncnt = 0, ccnt = 0;

stack&amp;lt;int&amp;gt; s;
vector&amp;lt;bool&amp;gt; ch;

int dfs(int x) {
    nnum[x] = ++ncnt;
    s.push(x);

    int tmp = nnum[x];

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(nnum[y] == 0) tmp = min(tmp, dfs(y));
        else if(!ch[y]) tmp = min(tmp, nnum[y]);
    }

    if(tmp == nnum[x]) {
        vector&amp;lt;int&amp;gt; v;
        ccnt++;

        while(true) {
            int y = s.top();
            s.pop();

            v.push_back(y);

            ch[y] = true;
            cnum[y] = ccnt;

            if(y == x) break;
        }

        sort(v.begin(), v.end());

        scc.push_back(v);
    }

    return tmp;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    while(T--) {
        int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

        adj.clear();
        adj.resize(N+1);

        while(M--) {
            int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

            adj[a+1].push_back(b+1);
        }

        nnum.clear();   nnum.resize(N+1);
        cnum.clear();   cnum.resize(N+1);
        ch.clear();     ch.resize(N+1);

        scc.clear();
        ncnt = ccnt = 0;

        for(int i=1; i&amp;lt;=N; i++)
            if(nnum[i] == 0) dfs(i);

        sort(scc.begin(), scc.end());

        vector&amp;lt;int&amp;gt; ind(N+1);

        for(int i=1; i&amp;lt;=N; i++)
            for(int j=0; j&amp;lt;adj[i].size(); j++) {
                int x = adj[i][j];

                if(cnum[i] != cnum[x]) ind[cnum[x]]++;
            }

        int cnt = 0, idx;
        for(int i=1; i&amp;lt;=ccnt; i++)
            if(ind[i] == 0) {
                cnt++;
                idx = i;
            }

        if(cnt == 1) {
            for(int i=1; i&amp;lt;=N; i++)
                if(cnum[i] == idx) cout &amp;lt;&amp;lt; i-1 &amp;lt;&amp;lt; &quot;\n&quot;;
        }
        else cout &amp;lt;&amp;lt; &quot;Confused\n&quot;;

        cout &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 6543번 : 그래프의 싱크&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;강한 결합 요소 (SCC)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래프의 모든 노드에서 어떤 노드로 도달하는 경로가 존재한다면, 이 노드를 그래프의 싱크라고 정의할 때, 주어진 그래프의 싱크 노드들을 모두 출력하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간선이 단방향 간선이므로, outdegree(외부로 나가는 간선의 수)가 0인 scc의 모든 원소들을 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;outdegree 값은 위의 도미노 문제에서 풀이한 것과 비슷한 방식으로, 모든 간선에 대해 검사할 때 서로 다른 scc 사이의 간선인 경우 해당 간선의 출발 노드에 outdegree를 1 더해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661234362593&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj, scc;
vector&amp;lt;int&amp;gt; nnum, cnum;
int ncnt = 0, ccnt = 0;

stack&amp;lt;int&amp;gt; s;
vector&amp;lt;bool&amp;gt; ch;

int dfs(int x) {
    nnum[x] = ++ncnt;
    s.push(x);

    int tmp = nnum[x];

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(nnum[y] == 0) tmp = min(tmp, dfs(y));
        else if(!ch[y]) tmp = min(tmp, nnum[y]);
    }

    if(tmp == nnum[x]) {
        vector&amp;lt;int&amp;gt; v;
        ccnt++;

        while(true) {
            int y = s.top();
            s.pop();

            v.push_back(y);

            ch[y] = true;
            cnum[y] = ccnt;

            if(y == x) break;
        }

        sort(v.begin(), v.end());

        scc.push_back(v);
    }

    return tmp;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    while(true) {
        int N; cin &amp;gt;&amp;gt; N;
        if(N == 0) break;

        int M; cin &amp;gt;&amp;gt; M;

        adj.clear();
        adj.resize(N+1);

        while(M--) {
            int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

            adj[a].push_back(b);
        }

        nnum.clear();   nnum.resize(N+1);
        cnum.clear();   cnum.resize(N+1);
        ch.clear();     ch.resize(N+1);

        scc.clear();
        ncnt = ccnt = 0;

        for(int i=1; i&amp;lt;=N; i++)
            if(nnum[i] == 0) dfs(i);

        sort(scc.begin(), scc.end());

        vector&amp;lt;int&amp;gt; oud(N+1);

        for(int i=1; i&amp;lt;=N; i++)
            for(int j=0; j&amp;lt;adj[i].size(); j++) {
                int x = adj[i][j];

                if(cnum[i] != cnum[x]) oud[cnum[i]]++;
            }

        for(int i=1; i&amp;lt;=N; i++)
            if(oud[cnum[i]] == 0) cout &amp;lt;&amp;lt; i &amp;lt;&amp;lt; &quot; &quot;;

        cout &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 4305번 : 성격 진단 테스트&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;강한 결합 요소 (SCC)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 5지선다 문제가 주어지고, 5개 중 가장 선호하는 항목을 고른다고 할 때, N개의 선호 관계를 활용하여 각 그룹의 원소들을 출력하여 같은 그룹의 어떤 두 원소를 뽑아도 모순 관계가 발생하게 그룹화시키는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(예를 들어 a, b 중에서 a를 뽑고, b, c 중에서 b를 뽑고, c, a 중에서 c를 뽑는다면 a &amp;gt; b &amp;gt; c &amp;gt; a로 모순이 발생하고, 출력으로 a b c를 출력해주면 된다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잘 생각해보면 SCC를 이루는 원소들끼리는 오갈 수 있는 사이클이 존재하므로, 단순히 SCC 그룹별로 원소들을 출력해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대문자 알파벳 하나씩만 입력으로 주어진다고 하였으므로, N은 최대 26이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나의 경우에는 무시하고 N = 26이라고 가정하고 scc를 돌린 다음에, scc[i][0] 값이 입력에 없었던 값이면 해당 줄은 skip하는 방식으로 구현하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661241758119&quot; class=&quot;arduino&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj, scc;
vector&amp;lt;int&amp;gt; nnum, cnum;
int ncnt = 0, ccnt = 0;

stack&amp;lt;int&amp;gt; s;
vector&amp;lt;bool&amp;gt; ch;

int dfs(int x) {
    nnum[x] = ++ncnt;
    s.push(x);

    int tmp = nnum[x];

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(nnum[y] == 0) tmp = min(tmp, dfs(y));
        else if(!ch[y]) tmp = min(tmp, nnum[y]);
    }

    if(tmp == nnum[x]) {
        vector&amp;lt;int&amp;gt; v;
        ccnt++;

        while(true) {
            int y = s.top();
            s.pop();

            v.push_back(y);

            ch[y] = true;
            cnum[y] = ccnt;

            if(y == x) break;
        }

        sort(v.begin(), v.end());

        scc.push_back(v);
    }

    return tmp;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    while(true) {
        int N = 26;

        int M; cin &amp;gt;&amp;gt; M;
        if(M == 0) break;

        adj.clear();
        adj.resize(N+1);

        vector&amp;lt;bool&amp;gt; u(N+1);

        while(M--) {
            vector&amp;lt;char&amp;gt; v(6);
            for(int i=0; i&amp;lt;6; i++) {
                cin &amp;gt;&amp;gt; v[i];

                u[v[i]-'A'+1] = true;
            }

            for(int i=0; i&amp;lt;6; i++) {
                if(v[i] == v[5]) continue;

                adj[v[i]-'A'+1].push_back(v[5]-'A'+1);
            }
        }

        nnum.clear();   nnum.resize(N+1);
        cnum.clear();   cnum.resize(N+1);
        ch.clear();     ch.resize(N+1);

        scc.clear();
        ncnt = ccnt = 0;

        for(int i=1; i&amp;lt;=N; i++)
            if(nnum[i] == 0) dfs(i);

        sort(scc.begin(), scc.end());

        for(int i=0; i&amp;lt;scc.size(); i++) {
            if(!u[scc[i][0]]) continue;

            for(int j=0; j&amp;lt;scc[i].size(); j++) cout &amp;lt;&amp;lt; char('A' + scc[i][j] - 1) &amp;lt;&amp;lt; &quot; &quot;;
            cout &amp;lt;&amp;lt; &quot;\n&quot;;
        }

        cout &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 25488번 : 토큰&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;강한 결합 요소 (SCC)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단방향 간선을 가진 그래프가 주어질 때, N개의 점의 목록 A와 B가 주어질 때, 처음에 A의 위치에 있던 N개의 토큰들을 그래프 간선만 따라서 이동시켜서 B의 위치들로 옮긴 뒤, 다시 A로 돌아올 수 있는지를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SCC를 돌린 후, A의 점들과 B의 점들이 각 SCC 그룹에 속하는 개수가 일치하면 Yes이고, 그 외에는 No이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여담으로 어제 대회 때 이 문제를 풀기 위해서 대회 시간에 SCC를 처음 공부해서 풀었다. (짤 줄은 몰랐지만 개념은 알고 있었기에 SCC로 풀리는 것이 너무 자명해보여서..)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661243791678&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj, scc;
int ncnt = 0, ccnt = 0;
stack&amp;lt;int&amp;gt; s;
vector&amp;lt;int&amp;gt; nnum, cnum;
vector&amp;lt;bool&amp;gt; ch;

int dfs(int x) {
    nnum[x] = ++ncnt;
    s.push(x);

    int tmp = nnum[x];

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(nnum[y] == 0) tmp = min(tmp, dfs(y));
        else if(!ch[y]) tmp = min(tmp, nnum[y]);
    }

    if(tmp == nnum[x]) {
        vector&amp;lt;int&amp;gt; v;
        ccnt++;

        while(true) {
            int y = s.top();
            s.pop();

            v.push_back(y);

            ch[y] = true;
            cnum[y] = ccnt;

            if(y == x) break;
        }

        sort(v.begin(), v.end());

        scc.push_back(v);
    }

    return tmp;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    adj.resize(N+1);

    while(M--) {
        int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

        adj[a].push_back(b);
    }

    nnum.resize(N+1);
    cnum.resize(N+1);
    ch.resize(N+1);

    for(int i=1; i&amp;lt;=N; i++)
        if(nnum[i] == 0) dfs(i);

    sort(scc.begin(), scc.end());

    int K; cin &amp;gt;&amp;gt; K;

    vector&amp;lt;int&amp;gt; v(ccnt+1), u(ccnt+1);

    for(int i=0; i&amp;lt;K; i++) {
        int x; cin &amp;gt;&amp;gt; x;

        v[cnum[x]]++;
    }

    for(int i=0; i&amp;lt;K; i++) {
        int x; cin &amp;gt;&amp;gt; x;

        u[cnum[x]]++;
    }

    if(v == u) cout &amp;lt;&amp;lt; &quot;YES\n&quot;;
    else cout &amp;lt;&amp;lt; &quot;NO\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 7042번 : Cow Ski Area&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;강한 결합 요소 (SCC)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;R x C 크기의 스키장의 높낮이가 주어질 때, 상하좌우로 이동하되 높은 곳에서 낮은 곳 또는 높이가 같은 곳으로만 이동이 가능하며, 특정 두 칸을 연결하는 리프트를 몇 개 설치하여 모든 칸 사이의 이동이 가능하도록 할 때 설치해야하는 최소 리프트의 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SCC를 돌려준 뒤 indegree가 0인 component의 수와 outdegree가 0인 component의 수 중 큰 것이 답이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지는 그래프 몇 개를 그려보고 빨리 파악을 했는데, 간단한 예외를 못 찾아서 30분은 헤맸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 component가 단 1개뿐이라면, 위의 풀이대로라면 답이 1이 나와야 하는데 이 경우는 답이 0이 되어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이와 같은 반례 처리에 주의하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1661245031505&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj, scc;
vector&amp;lt;int&amp;gt; nnum, cnum;
int ncnt = 0, ccnt = 0;

stack&amp;lt;int&amp;gt; s;
vector&amp;lt;bool&amp;gt; ch;

int dfs(int x) {
    nnum[x] = ++ncnt;
    s.push(x);

    int tmp = nnum[x];

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(nnum[y] == 0) tmp = min(tmp, dfs(y));
        else if(!ch[y]) tmp = min(tmp, nnum[y]);
    }

    if(tmp == nnum[x]) {
        vector&amp;lt;int&amp;gt; v;
        ccnt++;

        while(true) {
            int y = s.top();
            s.pop();

            v.push_back(y);

            ch[y] = true;
            cnum[y] = ccnt;

            if(y == x) break;
        }

        sort(v.begin(), v.end());

        scc.push_back(v);
    }

    return tmp;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int C, R; cin &amp;gt;&amp;gt; C &amp;gt;&amp;gt; R;

    vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; v(R+1, vector&amp;lt;int&amp;gt;(C+1));

    for(int i=1; i&amp;lt;=R; i++)
        for(int j=1; j&amp;lt;=C; j++) cin &amp;gt;&amp;gt; v[i][j];

    int N = R * C;

    adj.resize(N+1);

    int di[4] = {1, -1, 0, 0};
    int dj[4] = {0, 0, 1, -1};

    for(int i=1; i&amp;lt;=R; i++)
        for(int j=1; j&amp;lt;=C; j++)
            for(int k=0; k&amp;lt;4; k++) {
                int ni = i + di[k];
                int nj = j + dj[k];

                if(ni &amp;lt;= 0 || nj &amp;lt;= 0 || ni &amp;gt; R || nj &amp;gt; C) continue;

                if(v[i][j] &amp;gt;= v[ni][nj]) adj[(i-1)*C + j].push_back((ni-1)*C + nj);
            }

    nnum.resize(N+1);
    cnum.resize(N+1);
    ch.resize(N+1);

    for(int i=1; i&amp;lt;=N; i++)
        if(nnum[i] == 0) dfs(i);

    sort(scc.begin(), scc.end());

    if(ccnt == 1) {
        cout &amp;lt;&amp;lt; 0 &amp;lt;&amp;lt; &quot;\n&quot;;
        return 0;
    }

    vector&amp;lt;int&amp;gt; ind(N+1), oud(N+1);

    for(int i=1; i&amp;lt;=N; i++)
        for(int j=0; j&amp;lt;adj[i].size(); j++) {
            int x = adj[i][j];

            if(cnum[i] != cnum[x]) {
                ind[cnum[x]]++;
                oud[cnum[i]]++;
            }
        }

    int incnt = 0, oucnt = 0;
    for(int i=1; i&amp;lt;=ccnt; i++) {
        if(ind[i] == 0) incnt++;
        if(oud[i] == 0) oucnt++;
    }

    int ans = max(incnt, oucnt);

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/알고리즘 공부 내용 정리</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/616</guid>
      <comments>https://restudycafe.tistory.com/616#entry616comment</comments>
      <pubDate>Tue, 23 Aug 2022 11:27:02 +0900</pubDate>
    </item>
    <item>
      <title>백준 BOJ 다양한 해시맵(map) 활용 문제들 solution 220822</title>
      <link>https://restudycafe.tistory.com/615</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 24411번 : Stamp Combinations&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;누적 합, 해시를 사용한 집합과 맵&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;길이 N인 수열에 대해, 앞의 부분합과 뒤의 부분합의 합으로 쿼리로 입력된 값을 만들 수 있는지 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 N x Q(쿼리의 수) &amp;le; 10^7이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;누적 합을 사용하는 것은 확실해보이나, 누적 합을 사용하더라도 O(N^2)에 돌아간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 시간 복잡도를 조금 더 개선할 방법을 찾아보아야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1373&quot; data-origin-height=&quot;1737&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Oe1Jt/btrKkhpJHBd/B83bl0KUgiyauAONnS2v80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Oe1Jt/btrKkhpJHBd/B83bl0KUgiyauAONnS2v80/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Oe1Jt/btrKkhpJHBd/B83bl0KUgiyauAONnS2v80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOe1Jt%2FbtrKkhpJHBd%2FB83bl0KUgiyauAONnS2v80%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;468&quot; height=&quot;592&quot; data-origin-width=&quot;1373&quot; data-origin-height=&quot;1737&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;v_i를 1 ~ i번째 원소의 합이라고 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 뒤쪽 부분의 합은 v_N - v_i이고, 앞쪽 부분은 쿼리 값이 x라고 했을 때 x - (v_N - v_i)이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;map을 활용하여 v_0 ~ v_N 값들을 모두 저장해두고 &lt;span style=&quot;color: #ee2323;&quot;&gt;m[x - (v_N - v_i)]가 체크되어있는지만 확인&lt;/span&gt;하면 O(1) 시간에 확인이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반례로 가능한 것은 아래쪽의 그림과 같이 두 부분이 겹쳐버리는 것인데, 이런 경우는 continue로 넘기든 범위를 안 겹치게 설정해주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;급하게 푸느라 그림이 조금 더러운데, 빗금(수열 전체의 앞 부분, 뒷 부분) 부분만 보면 대충 이해할 수 있을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661155048739&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    vector&amp;lt;int&amp;gt; v(N+1);
    for(int i=1; i&amp;lt;=N; i++) {
        int x; cin &amp;gt;&amp;gt; x;

        v[i] = v[i-1] + x;
    }

    unordered_map&amp;lt;int, bool&amp;gt; m;
    for(int i=0; i&amp;lt;=N; i++) m[v[i]] = true;

    while(M--) {
        int x; cin &amp;gt;&amp;gt; x;

        bool check = false;

        for(int i=0; i&amp;lt;=N; i++) {
            if(x - (v[N] - v[i]) &amp;gt; v[i]) continue;

            if(m[x - (v[N] - v[i])]) {
                check = true;
                break;
            }
        }

        if(check) cout &amp;lt;&amp;lt; &quot;Yes\n&quot;;
        else cout &amp;lt;&amp;lt; &quot;No\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 3557번 : Homo or Hetero?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;트리를 사용한 집합과 맵&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;집합에 insert 또는 delete로 원소를 추가/제거할 때, 매 쿼리마다 집합이 어디에 속하는지를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제에서 정의한 집합의 종류는 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;hetero : 원소가 두 개 이상이고 다른 원소가 존재하는 집합&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;homo : 원소가 두 개 이상이고 같은 원소가 존재하는 집합&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;both: hetero이면서 동시에 homo인 집합&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;neither : hetero도 아니고 homo도 아닌 집합&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;multiset을 이용하여 구현이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원소를 하나 erase할 때 주의할 점은 s.erase(x)와 같이 수행해주면 여러 개의 x를 가진 경우에도 모두 삭제가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 s.erase(s.find(x))와 같이 작성해주어야 원소 x가 하나씩 삭제가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자세한 구현은 아래의 코드를 참조하는 편이 더 나을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661142149594&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    multiset&amp;lt;int&amp;gt; s;
    int cnt = 0;

    while(N--) {
        string str; cin &amp;gt;&amp;gt; str;
        int x; cin &amp;gt;&amp;gt; x;

        if(str == &quot;insert&quot;) {
            if(s.count(x) == 0) cnt++;
            s.insert(x);
        }
        else if(str == &quot;delete&quot;) {
            if(s.count(x) &amp;gt; 0) {
                s.erase(s.find(x));
                if(s.count(x) == 0) cnt--;
            }
        }

        if(s.size() &amp;gt;= 2 &amp;amp;&amp;amp; s.size() &amp;gt; cnt &amp;amp;&amp;amp; cnt &amp;gt;= 2) cout &amp;lt;&amp;lt; &quot;both\n&quot;;
        else if(s.size() &amp;gt;= 2 &amp;amp;&amp;amp; s.size() == cnt) cout &amp;lt;&amp;lt; &quot;hetero\n&quot;;
        else if(s.size() &amp;gt;= 2 &amp;amp;&amp;amp; cnt == 1) cout &amp;lt;&amp;lt; &quot;homo\n&quot;;
        else if(s.size() &amp;lt;= 1) cout &amp;lt;&amp;lt; &quot;neither\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 11313번 : Best Buddies&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;정렬, 해시를 사용한 집합과 맵&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N명의 사람의 성과 이름이 주어지고, 이름을 last name의 사전순, last name이 같으면 first name의 사전 순으로 정렬한 뒤 앞에서부터 3명씩 같은 팀이 된다고 할 때, M개의 쿼리에 대해 한 사람의 이름이 주어지면 위에서 말한 정렬 순으로 다른 팀원 두 명의 이름을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 정렬은 기준이 주어졌으므로 sort의 cmp 함수를 직접 정의하여 정렬해줄 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 하나의 팀원의 이름에 대해 나머지 두 팀원의 이름을 구해주어야 하는데, N이 10만 이하이므로 O(N^2)과 같은 방법으로는 불가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 &lt;span style=&quot;color: #ee2323;&quot;&gt;map 2개를 선언하여, m[str] 값이 팀원 이름이 되도록 저장&lt;/span&gt;해주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 O(1) 시간에 답을 찾을 수 있으므로 O(M)에 모든 쿼리를 처리해줄 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661142968027&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

bool cmp(pair&amp;lt;string, string&amp;gt; a, pair&amp;lt;string, string&amp;gt; b) {
    if(a.second != b.second) return a.second &amp;lt; b.second;
    else return a.first &amp;lt; b.first;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;pair&amp;lt;string, string&amp;gt;&amp;gt; v(N);

    for(int i=0; i&amp;lt;N; i++)
        cin &amp;gt;&amp;gt; v[i].first &amp;gt;&amp;gt; v[i].second;

    sort(v.begin(), v.end(), cmp);

    unordered_map&amp;lt;string, string&amp;gt; m1, m2;

    for(int i=0; i&amp;lt;N; i+=3) {
        string a = v[i].first + ' ' + v[i].second;
        string b = v[i+1].first + ' ' + v[i+1].second;
        string c = v[i+2].first + ' ' + v[i+2].second;

        m1[a] = b;
        m2[a] = c;

        m1[b] = a;
        m2[b] = c;

        m1[c] = a;
        m2[c] = b;
    }

    int M; cin &amp;gt;&amp;gt; M;
    cin.ignore();

    while(M--) {
        string str; getline(cin, str);

        cout &amp;lt;&amp;lt; m1[str] &amp;lt;&amp;lt; &quot;\n&quot; &amp;lt;&amp;lt; m2[str] &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 16524번 : Database of Clients&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;해시를 사용한 집합과 맵&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 이메일들이 주어질 때, 실제 사용자 수가 몇인지를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(이메일에서 @ 앞의 +가 나오면 + ~ @ 사이의 문자들은 모두 무시되며, @ 앞에 나오는 . 역시 무시된다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tmp라는 문자열에 무시되는 문자들을 제외하고 추가하여, map으로 중복 체크를 해주는 방식을 이용하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 개의 bool 변수 a와 p를 이용하여 @와 +가 언제 나왔는지를 체크한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;+가 나왔다면 @가 나오기 전까지는 모두 무시해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@가 나왔으면 그 뒤의 모든 문자를 추가해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@가 나오기 전의 .은 무시해주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661128908018&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    map&amp;lt;string, bool&amp;gt; m;
    int ans = 0;

    while(N--) {
        string str; cin &amp;gt;&amp;gt; str;

        string tmp = &quot;&quot;;
        bool a = false, p = false;

        for(int i=0; i&amp;lt;str.length(); i++) {
            if(str[i] == '@') {
                a = true;
                p = false;
            }
            else if(str[i] == '+') p = true;
            else if(p) continue;
            else if(str[i] == '.') {
                if(a) tmp += str[i];
                else continue;
            }
            else tmp += str[i];
        }

        if(!m[tmp]) ans++;

        m[tmp] = true;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 21396번 : 이진수 더하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;해시를 사용한 집합과 맵&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주어진 N개의 수 중에서 두 수를 골라 받아올림이 없는 이진수 덧셈을 하여 M이 되는 조합의 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;map을 사용하면 쉽게 풀 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 받아올림이 없는 이진수 덧셈은 xor 연산을 한 것과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 N개의 수를 앞에서부터 검사하며 m[x] 값을 더하고, 더한 이후에 m[M ^ x]에 1씩 더해주면 다음에 M ^ x가 N개의 수 중 하나로 들어올 경우 count가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 방식으로 풀면 O(N) 시간에 모든 조합의 수를 찾을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661139319878&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    while(T--) {
        int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

        unordered_map&amp;lt;int, int&amp;gt; m;
        int ans = 0;

        while(N--) {
            int x; cin &amp;gt;&amp;gt; x;

            ans += m[x];

            m[x ^ M]++;
        }

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 21980번 : 비슷한 번호판&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;해시를 사용한 집합과 맵&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알파벳으로만 이루어진 번호판에 대해 구성 문자와 길이가 같고, 대문자의 개수가 같으면 비슷한 번호판이라고 한다면 주어진 N개의 번호판 중 비슷한 번호판은 몇 쌍인지 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 번호판을 알파벳 순으로 정렬하는 것은 답에 영향을 주지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 대문자의 수만 count 해둔다면 모든 알파벳을 소문자로 바꾸어도 상관이 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 이용하여 모든 번호판을 소문자로 바꾸고 정렬한 뒤, map을 &amp;lt;소문자 정렬 문자열, 대문자 개수&amp;gt; &amp;rarr; 번호판 개수와 같이 설정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 N개의 번호판을 순차적으로 검사하며 해당 번호판과 같은 문자열과 대문자 개수에 해당되는 map의 값만큼 답에 더해주면서 답을 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661140193275&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    while(T--) {
        int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

        map&amp;lt;pair&amp;lt;string, int&amp;gt;, int&amp;gt; m;
        int ans = 0;

        while(N--) {
            string str; cin &amp;gt;&amp;gt; str;

            int cnt = 0;

            for(int i=0; i&amp;lt;M; i++) {
                if(str[i] &amp;gt;= 'A' &amp;amp;&amp;amp; str[i] &amp;lt;= 'Z') {
                    str[i] += 'a' - 'A';
                    cnt++;
                }
            }

            sort(str.begin(), str.end());

            ans += m[{str, cnt}];

            m[{str, cnt}]++;
        }

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 4358번 : 생태학&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;b&gt;&lt;span style=&quot;color: #666666;&quot;&gt;Silver II&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;해시를 사용한 집합과 맵&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;식물들의 목록이 주어질 때, 각 식물을 사전 순으로 출력하며 각 식물이 개수만큼 차지하는 비중을 백분위로 소수점 아래 4자리까지 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;map을 사용하여 어렵지 않게 해결할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름이 나올 때마다 map[str] 값을 1씩 늘려주고, 마지막에 전체 나온 항목의 개수로 나눈 값 x 100을 하여 퍼센트 값을 구할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661128439280&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    string str;

    vector&amp;lt;string&amp;gt; v;
    map&amp;lt;string, int&amp;gt; m;
    int tot = 0;

    while(getline(cin, str)) {
        if(m[str] == 0) v.push_back(str);

        m[str]++;
        tot++;
    }

    sort(v.begin(), v.end());

    cout &amp;lt;&amp;lt; fixed;
    cout.precision(4);

    for(int i=0; i&amp;lt;v.size(); i++)
        cout &amp;lt;&amp;lt; v[i] &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; (double)m[v[i]] * 100 / tot &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 21208번 : Gratitude&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;정렬, 해시를 사용한 집합과 맵&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3N개의 목록이 주어지고, 이들 중 가장 빈도가 높은 것이 먼저, 빈도가 같다면 마지막에 나온 것이 뒤 순서일 경우 먼저 나오도록 정렬하였을 때 앞의 M개의 목록을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;map 2개를 사용하여 각각 나온 횟수, 그리고 마지막으로 나온 위치를 저장하여 정렬해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 나온 목록의 종류가 M보다 작은 경우가 있으므로, min(v.size(), M)까지만 출력해주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661132443998&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

unordered_map&amp;lt;string, int&amp;gt; m, idx;

bool cmp(string a, string b) {
    if(m[a] != m[b]) return m[a] &amp;gt; m[b];
    else return idx[a] &amp;gt; idx[b];
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;
    cin.ignore();

    vector&amp;lt;string&amp;gt; v;

    for(int i=0; i&amp;lt;N*3; i++) {
        string str; getline(cin, str);

        if(m[str] == 0) v.push_back(str);

        m[str]++;
        idx[str] = i;
    }

    sort(v.begin(), v.end(), cmp);

    for(int i=0; i&amp;lt;min((int)v.size(), M); i++) cout &amp;lt;&amp;lt; v[i] &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 24653번 : Announcements&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;해시를 사용한 집합과 맵&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 광고가 v_i번째 날짜에 게재되고, M일마다 광고가 모두 수거될 때, 모든 광고를 보기 위해서 학교에 가야하는 날의 최소 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;M일에 광고가 수거된다면 1 ~ M-1번째 날에 광고를 보러가면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, N개의 값들을 M으로 나눈 몫이 몇 가지 종류인지를 물어보는 문제임을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 map을 이용하여 v_i / M이 나왔던 값인지를 체크하고 만약 나오지 않았다면 답에 1을 더해주는 방식을 반복하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661131357800&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;int&amp;gt; v(N);
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];

    int M; cin &amp;gt;&amp;gt; M;

    unordered_map&amp;lt;int, bool&amp;gt; m;
    int ans = 0;

    for(int i=0; i&amp;lt;N; i++) {
        int x = v[i] / M;

        if(!m[x]) ans++;

        m[x] = true;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 18295번 : Ants&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;해시를 사용한 집합과 맵&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주어진 수들 중에서 나타나지 않은 가장 작은 0 이상의 정수를 찾는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 매우 큰 정수가 입력으로 들어올 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;map을 이용하여 정수들의 입력 여부를 체크할 것인데, 매우 큰 정수가 입력될 경우 오류를 발생시킬 수 있으므로 일단은 문자열로 입력받은 뒤 특정 자리수 이상의 길이를 가질 경우 continue 처리를 해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 외의 경우에는 map에 기록을 해주고, 그 다음 0부터 검사하면서 map 값이 false인 최초의 정수에 대해 출력을 해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661129292201&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    unordered_map&amp;lt;int, bool&amp;gt; m;

    while(N--) {
        string x; cin &amp;gt;&amp;gt; x;

        if(x.length() &amp;gt; 7) continue;

        m[stoi(x)] = true;
    }

    for(int i=0; ; i++) {
        if(!m[i]) {
            cout &amp;lt;&amp;lt; i &amp;lt;&amp;lt; &quot;\n&quot;;
            break;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 5588번 : 별자리 찾기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;브루트포스&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 별의 좌표가 주어지고, 이들이 같은 거리만큼 평행이동을 했으며 N개보다 많은 M개의 별이 주어질 때 N개의 별이 얼마만큼 평행이동을 했는지를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N이 500 이하라서 브루트포스 알고리즘으로 풀린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;map에 0번째 별을 기준으로 다른 별들의 간격을 저장하고, M개의 별들 중에 이러한 간격을 모두 가지는 것이 있다면 그 별이 0번째 별인 것이므로, 아까의 0번째 별의 좌표에서 얼마나 이동했는지 계산해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661143180177&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;pair&amp;lt;int, int&amp;gt;&amp;gt; v(N);

    for(int i=0; i&amp;lt;N; i++)
        cin &amp;gt;&amp;gt; v[i].first &amp;gt;&amp;gt; v[i].second;

    map&amp;lt;pair&amp;lt;int, int&amp;gt;, bool&amp;gt; m;

    for(int i=0; i&amp;lt;N; i++)
        m[{v[i].first - v[0].first, v[i].second - v[0].second}] = true;

    int M; cin &amp;gt;&amp;gt; M;

    vector&amp;lt;pair&amp;lt;int, int&amp;gt;&amp;gt; u(M);

    for(int i=0; i&amp;lt;M; i++)
        cin &amp;gt;&amp;gt; u[i].first &amp;gt;&amp;gt; u[i].second;

    for(int i=0; i&amp;lt;M; i++) {
        int cnt = 0;

        for(int j=0; j&amp;lt;M; j++) {
            if(m[{u[j].first - u[i].first, u[j].second - u[i].second}]) cnt++;
        }

        if(cnt &amp;gt;= N) {
            cout &amp;lt;&amp;lt; u[i].first - v[0].first &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; u[i].second - v[0].second &amp;lt;&amp;lt; &quot;\n&quot;;

            break;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/알고리즘 공부 내용 정리</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/615</guid>
      <comments>https://restudycafe.tistory.com/615#entry615comment</comments>
      <pubDate>Mon, 22 Aug 2022 10:07:10 +0900</pubDate>
    </item>
    <item>
      <title>중간에서 만나기 : 밋 인더 미들 알고리즘 풀이 모음 220821</title>
      <link>https://restudycafe.tistory.com/614</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 16287번 : Parcel&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;중간에서 만나기 (밋 인더 미들), DP&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 물품 중 &quot;서로 다른&quot; 물품 4개를 골라 그 무게의 합이 M이 되도록 하는 경우가 있는지 확인하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 N이 5,000이므로, O(N^4) 같은 방법은 안 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 원소는 최대 20만이므로, 두 원소의 합을 배열에 저장하고, 나머지 두 원소의 합을 배열의 기록을 이용하여 비교해보는 방식을 사용해볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;O(N^2) 시간에 두 원소의 합을 구성하는 원소의 주소를 u, w에 저장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로 O(N^2) 시간에 나머지 두 원소의 합이 기록된 것들 중에서 주소가 둘 다 겹치지 않는 것이 있으면, YES를 정답으로 출력해주면 되고 그러한 조합이 하나도 없을 경우 NO를 출력해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661088830240&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int M, N; cin &amp;gt;&amp;gt; M &amp;gt;&amp;gt; N;

    vector&amp;lt;int&amp;gt; v(N);
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];

    vector&amp;lt;int&amp;gt; u(5e5, -1), w(5e5, -1);

    for(int i=0; i&amp;lt;N; i++)
        for(int j=i+1; j&amp;lt;N; j++) {
            int sum = v[i] + v[j];

            if(u[sum] != -1 || w[sum] != -1) continue;

            u[sum] = i;
            w[sum] = j;
        }

    for(int i=0; i&amp;lt;N; i++)
        for(int j=i+1; j&amp;lt;N; j++) {
            int sum = M - (v[i] + v[j]);

            if(sum &amp;lt;= 0 || sum &amp;gt;= 400000) continue;
            if(u[sum] == -1 || w[sum] == -1) continue;
            if(u[sum] == i || w[sum] == j || u[sum] == j || w[sum] == i) continue;

            cout &amp;lt;&amp;lt; &quot;YES\n&quot;;

            return 0;
        }

    cout &amp;lt;&amp;lt; &quot;NO\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 10767번 : Palindromic Paths&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;중간에서 만나기 (밋 인더 미들)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N x N 배열이 주어질 때, 맨 왼쪽 위에서 맨 오른쪽 아래로 이동하면서 거친 알파벳들을 순서대로 합쳐 만들어진 문자열이 회문인 것의 종류의 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N이 최대 18이므로, 지나쳐야하는 경로의 길이는 최대 18 x 2 - 1 = 37이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;O(2^37)은 시간 초과를 발생시키므로, 시간을 줄일 필요가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 생각한 풀이는 (i, N-1-i) 지점이 경로의 중간이 되므로, 모든 i에 대해 (i, N-1-i)에서 왼쪽 위로 가면서 만들어지는 문자열과 오른쪽 아래로 가면서 만들어지는 문자열이 같은지 검사하면 된다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 할 경우 O(2 x 2^17)로 시간을 단축시킬 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 중복을 없애주기 위해서 벡터에 모두 넣은 뒤 정렬 및 중복 제거를 하여 마지막에 벡터에 남은 원소들의 수로 답을 찾아주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661071112043&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

int N;
vector&amp;lt;vector&amp;lt;char&amp;gt;&amp;gt; v;
vector&amp;lt;string&amp;gt; u, w;

void f(int x, int y, string s) {
    if(x == 0 &amp;amp;&amp;amp; y == 0) {
        u.push_back(s);

        return;
    }

    int dx[2] = {-1, 0};
    int dy[2] = {0, -1};

    for(int i=0; i&amp;lt;2; i++) {
        int nx = x + dx[i];
        int ny = y + dy[i];

        if(nx &amp;lt; 0 || ny &amp;lt; 0) continue;

        f(nx, ny, s + v[nx][ny]);
    }
}

void g(int x, int y, string s) {
    if(x == N-1 &amp;amp;&amp;amp; y == N-1) {
        w.push_back(s);

        return;
    }

    int dx[2] = {1, 0};
    int dy[2] = {0, 1};

    for(int i=0; i&amp;lt;2; i++) {
        int nx = x + dx[i];
        int ny = y + dy[i];

        if(nx &amp;gt;= N || ny &amp;gt;= N) continue;

        g(nx, ny, s + v[nx][ny]);
    }
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    cin &amp;gt;&amp;gt; N;

    v.resize(N, vector&amp;lt;char&amp;gt;(N));

    for(int i=0; i&amp;lt;N; i++)
        for(int j=0; j&amp;lt;N; j++) cin &amp;gt;&amp;gt; v[i][j];

    vector&amp;lt;string&amp;gt; vv;

    for(int i=0; i&amp;lt;N; i++) {
        u.clear();
        w.clear();

        f(i, N-1-i, &quot;&quot;);
        g(i, N-1-i, &quot;&quot;);

        sort(u.begin(), u.end());
        sort(w.begin(), w.end());

        for(int j=0; j&amp;lt;u.size(); j++) {
            if(upper_bound(w.begin(), w.end(), u[j]) - lower_bound(w.begin(), w.end(), u[j]) &amp;gt; 0) {
                string s = u[j];

                reverse(s.begin(), s.end());

                vv.push_back(s + v[i][N-1-i] + u[j]);
            }
        }
    }

    sort(vv.begin(), vv.end());
    vv.erase(unique(vv.begin(), vv.end()), vv.end());

    cout &amp;lt;&amp;lt; vv.size() &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 9007번 : 카누 선수&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;b&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;Gold III&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;중간에서 만나기 (밋 인더 미들)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 반에 N명씩으로 구성된 학생들의 몸무게가 주어질 때, 각 반에서 1명씩 뽑아 총 4명의 학생들의 몸무게의 합이 M과 가장 가깝게 하는 합을 구하는 문제이다. (이 때 M - x = y - M이라면 x를 선택한다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N이 1,000 이하이므로, 두 반씩 골라서 모든 가능한 몸무게의 조합을 두 개의 벡터에 저장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 각 u[i]에 대해 M - u[i]에 가장 가까운 값을 w에서 이분 탐색으로 찾으면 O(N^2 log (N^2))에 풀 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심은 &quot;가장 가까운 합&quot;을 어떻게 찾느냐는 것인데, 이것은 lower_bound로 찾은 주소와 그 주소 - 1 둘을 모두 체크해보아서 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;lower_bound가 x 이상인 최솟값이라면, lower_bound - 1의 값은 x 미만인 최댓값&lt;/span&gt;일 것이기 때문이다. (이터레이터라 주소와 개념이 다르긴 하지만 대충 이해하시면 됩니다..)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661073544350&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    while(T--) {
        int M, N; cin &amp;gt;&amp;gt; M &amp;gt;&amp;gt; N;

        vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; v(4, vector&amp;lt;int&amp;gt;(N));

        for(int i=0; i&amp;lt;4; i++)
            for(int j=0; j&amp;lt;N; j++) cin &amp;gt;&amp;gt; v[i][j];

        vector&amp;lt;int&amp;gt; u, w;

        for(int i=0; i&amp;lt;N; i++)
            for(int j=0; j&amp;lt;N; j++) u.push_back(v[0][i] + v[1][j]);

        for(int i=0; i&amp;lt;N; i++)
            for(int j=0; j&amp;lt;N; j++) w.push_back(v[2][i] + v[3][j]);

        sort(u.begin(), u.end());
        sort(w.begin(), w.end());

        int ans = INT_MAX;

        for(int i=0; i&amp;lt;u.size(); i++) {
            int x = lower_bound(w.begin(), w.end(), M - u[i]) - w.begin();

            if(x &amp;lt; w.size()) {
                if(abs(u[i] + w[x] - M) &amp;lt; abs(ans - M)) ans = u[i] + w[x];
                else if(abs(u[i] + w[x] - M) == abs(ans - M)) ans = min(ans, u[i] + w[x]);
            }

            if(x &amp;gt; 0) {
                if(abs(u[i] + w[x-1] - M) &amp;lt; abs(ans - M)) ans = u[i] + w[x-1];
                else if(abs(u[i] + w[x-1] - M) == abs(ans - M)) ans = min(ans, u[i] + w[x-1]);
            }
        }

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 12045번 : Robot Rock Band (Large)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;중간에서 만나기 (밋 인더 미들)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4개의 그룹이 각각 N개의 값을 가졌을 때, 4개에서 각각 1개의 값들을 골라 xor한 값이 M인 조합의 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 카누 선수 문제와 동일하기 풀이하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;xor 연산의 경우 교환 법칙이 성립하므로 벡터 w에서 M ^ u[i] 값을 가지는 것의 개수를 이분 탐색으로 찾아주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661074025691&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    for(int t=1; t&amp;lt;=T; t++) {
        int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

        vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; v(4, vector&amp;lt;int&amp;gt;(N));

        for(int i=0; i&amp;lt;4; i++)
            for(int j=0; j&amp;lt;N; j++) cin &amp;gt;&amp;gt; v[i][j];

        vector&amp;lt;int&amp;gt; u, w;

        for(int i=0; i&amp;lt;N; i++)
            for(int j=0; j&amp;lt;N; j++) u.push_back(v[0][i] ^ v[1][j]);

        for(int i=0; i&amp;lt;N; i++)
            for(int j=0; j&amp;lt;N; j++) w.push_back(v[2][i] ^ v[3][j]);

        sort(u.begin(), u.end());
        sort(w.begin(), w.end());

        int ans = 0;

        for(int i=0; i&amp;lt;u.size(); i++)
            ans += upper_bound(w.begin(), w.end(), M ^ u[i]) - lower_bound(w.begin(), w.end(), M ^ u[i]);

        cout &amp;lt;&amp;lt; &quot;Case #&quot; &amp;lt;&amp;lt; t &amp;lt;&amp;lt; &quot;: &quot; &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;

    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여담으로 이 문제를 풀면 &lt;b&gt;백준 BOJ 12044번 : Robot Rock Band (Small)&lt;/b&gt;을 풀이할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 23538번 : Easy Equation&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;중간에서 만나기 (밋 인더 미들)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;x^5 + y^4 + z^3 + w^2 + t = N을 만족하는 양의 정수 (x, y, z, w, t)의 순서쌍의 개수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 x^5 + y^4 + z^3 + w^2 &amp;lt; N을 만족하기만 하면 t는 자동으로 결정된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기 때문에 위 4개의 변수의 순서쌍을 구하는데에 초점을 맞추면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;x^5 &amp;lt; N을 만족하는 x들과 w^2 &amp;lt; N을 만족하는 w들을 구해 x + w의 조합을 벡터 u에 저장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;y^4 &amp;lt; N을 만족하는 y들과 z^3 &amp;lt; N을 만족하는 z들을 구해 y + z의 조합을 벡터 w에 저장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 나누는 이유는 u와 w의 size를 최대한 비슷하게 맞추기 위해서이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 밋 인더 미들로 조합의 수를 구할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661074638173&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; v(4);

    for(int i=1; i*i*i*i*i&amp;lt;N; i++) v[0].push_back(i*i*i*i*i);
    for(int i=1; i*i*i*i&amp;lt;N; i++) v[1].push_back(i*i*i*i);
    for(int i=1; i*i*i&amp;lt;N; i++) v[2].push_back(i*i*i);
    for(int i=1; i*i&amp;lt;N; i++) v[3].push_back(i*i);

    vector&amp;lt;int&amp;gt; u, w;

    for(int i=0; i&amp;lt;v[1].size(); i++)
        for(int j=0; j&amp;lt;v[2].size(); j++)
                u.push_back(v[1][i] + v[2][j]);

    for(int i=0; i&amp;lt;v[0].size(); i++)
        for(int j=0; j&amp;lt;v[3].size(); j++)
                w.push_back(v[0][i] + v[3][j]);

    sort(u.begin(), u.end());
    sort(w.begin(), w.end());

    int ans = 0;

    for(int i=0; i&amp;lt;u.size(); i++) {
        ans += lower_bound(w.begin(), w.end(), N - u[i]) - w.begin();
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 5526번 : ダーツ (Darts)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;중간에서 만나기 (밋 인더 미들)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4개 이하의 다트를 던져 N개의 점수 중 하나를 받고 그 합을 M점 이하의 최대한 가까운 점수로 만들려고 할 때, 그 점수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 밋 인더 미들로 풀이하면 되지만, 이 문제에서는 다트의 일부를 던지지 않아도 되므로, 벡터에 0을 추가해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;벡터에서 0이 선택된다면 그 다트는 던지지 않는 것으로 생각할 수 있기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이분 탐색에서 x를 초과하는 최소 주소 - 1의 값을 검사해서 최댓값을 갱신해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661075386752&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    vector&amp;lt;int&amp;gt; v;
    v.push_back(0);

    for(int i=0; i&amp;lt;N; i++) {
        int x; cin &amp;gt;&amp;gt; x;

        v.push_back(x);
    }

    vector&amp;lt;int&amp;gt; u;

    for(int i=0; i&amp;lt;v.size(); i++)
        for(int j=0; j&amp;lt;v.size(); j++) u.push_back(v[i] + v[j]);

    vector&amp;lt;int&amp;gt; w(u);

    sort(u.begin(), u.end());
    sort(w.begin(), w.end());

    int ans = 0;

    for(int i=0; i&amp;lt;u.size(); i++) {
        int x = upper_bound(w.begin(), w.end(), M - u[i]) - w.begin();

        if(x == 0) continue;

        ans = max(ans, u[i] + w[x-1]);
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 10958번 : Ice Hockey World Championship&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;중간에서 만나기 (밋 인더 미들)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N = 40 이하일 때, N개의 티켓의 가격의 합이 M원 이하가 되도록 하는 조합의 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 개의 티켓도 사지 않는 경우도 경우에 포함된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N을 둘로 나누어 밋 인더 미들을 써주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;밋 인더 미들의 정석적인 문제라서 크게 설명할 부분은 없고 똑같이 풀이해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661085483939&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

int N, M;
vector&amp;lt;int&amp;gt; v, u, w;

void f(int idx, int sum) {
    if(idx == N/2) {
        u.push_back(sum);
        return;
    }

    f(idx + 1, sum);
    f(idx + 1, sum + v[idx]);
}

void g(int idx, int sum) {
    if(idx == N) {
        w.push_back(sum);
        return;
    }

    g(idx + 1, sum);
    g(idx + 1, sum + v[idx]);
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    v.resize(N);
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];

    f(0, 0);
    g(N/2, 0);

    sort(u.begin(), u.end());
    sort(w.begin(), w.end());

    int ans = 0;

    for(int i=0; i&amp;lt;u.size(); i++)
        ans += upper_bound(w.begin(), w.end(), M - u[i]) - w.begin();

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 6099번 : Exams&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;중간에서 만나기 (밋 인더 미들)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 각 시험에서 얻을 수 있는 점수가 주어질 때, 일부 시험을 선택하여 M점 이상의 점수를 만드는 경우의 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N이 36 이하이므로 밋 인더 미들을 사용하여 풀이할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;0 ~ N/2까지 2^18 이하의 합으로 가능한 조합들을 모두 저장해주고, N/2 ~ N까지도 마찬가지로 해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 벡터 값을 정렬 해주고 (한 쪽만 해주면 된다.) 각 2^18 조합에 대해 나머지 2^18 조합들은 이분 탐색으로 몇 개의 값이 조건을 충족하는지 구해서 더해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;총 시간 복잡도는 O(2^(N/2) x (N/2))이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661063233629&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

int N, M;
vector&amp;lt;int&amp;gt; v, u, w;

void f(int idx, int sum) {
    if(idx == N/2) {
        u.push_back(sum);
        return;
    }

    f(idx + 1, sum);
    f(idx + 1, sum + v[idx]);
}

void g(int idx, int sum) {
    if(idx == N) {
        w.push_back(sum);
        return;
    }

    g(idx + 1, sum);
    g(idx + 1, sum + v[idx]);
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    v.resize(N);
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];

    f(0, 0);
    g(N/2, 0);

    sort(u.begin(), u.end());
    sort(w.begin(), w.end());

    int ans = 0;

    for(int i=0; i&amp;lt;u.size(); i++)
        ans += w.end() - lower_bound(w.begin(), w.end(), M - u[i]);

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 17637번 : Count Sqaures&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt; Silver IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;해시를 사용한 집합과 맵&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 수직선과 M개의 수평선이 그어졌을 때, 이들 중 4개를 선택하여 만들 수 있는 정사각형의 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, a_i - a_j = b_i - b_j의 쌍을 구하는 문제이다. (좌변의 i, j와 우변의 i, j는 다름)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;map으로 a_i - a_j의 모든 쌍을 구해놓고, b_i - b_j들의 모든 쌍들에 대해 map에 몇 개의 값이 저장되어 있는지 확인하여 답에 더해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661064955912&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    vector&amp;lt;int&amp;gt; v(N), u(M);

    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];
    for(int i=0; i&amp;lt;M; i++) cin &amp;gt;&amp;gt; u[i];

    sort(v.begin(), v.end());
    sort(u.begin(), u.end());

    unordered_map&amp;lt;int, int&amp;gt; m;

    for(int i=0; i&amp;lt;N; i++)
        for(int j=0; j&amp;lt;i; j++) m[v[i] - v[j]]++;

    int ans = 0;

    for(int i=0; i&amp;lt;M; i++)
        for(int j=0; j&amp;lt;i; j++) ans += m[u[i] - u[j]];

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/알고리즘 공부 내용 정리</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/614</guid>
      <comments>https://restudycafe.tistory.com/614#entry614comment</comments>
      <pubDate>Sun, 21 Aug 2022 15:57:39 +0900</pubDate>
    </item>
    <item>
      <title>트리를 사용한 집합과 맵 알고리즘 풀이들 정리 220820</title>
      <link>https://restudycafe.tistory.com/613</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ&amp;nbsp; 6325번 : Definite Values&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;트리를 사용한 집합과 맵&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 (변수) = (변수) 꼴의 수식이 주어지고, 처음에는 a만 값이 제대로 지정되었다고 할 때, 모든 등식이 적용된 이후 값이 제대로 지정된 변수의 목록을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;set을 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;a = b라는 등식에서, a가 값이 지정되지 않고 b가 지정되었다면 a는 제대로 된 값이 지정된다. (set에 insert 해준다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반대로 a가 값이 지정되고 b가 지정되지 않았다면 a의 값은 쓰레기 값으로 덮어진다. (set에서 erase 해준다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 과정을 N번 반복한 다음 set의 모든 원소들을 출력해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660976519703&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    for(int t=1; ; t++) {
        int N; cin &amp;gt;&amp;gt; N;
        if(N == 0) break;

        set&amp;lt;string&amp;gt; s;
        s.insert(&quot;a&quot;);

        while(N--) {
            string a, op, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; op &amp;gt;&amp;gt; b;

            if(s.count(a) == 0 &amp;amp;&amp;amp; s.count(b) &amp;gt; 0) s.insert(a);
            else if(s.count(a) &amp;gt; 0 &amp;amp;&amp;amp; s.count(b) == 0) s.erase(a);
        }

        cout &amp;lt;&amp;lt; &quot;Program #&quot; &amp;lt;&amp;lt; t &amp;lt;&amp;lt; &quot;\n&quot;;

        if(s.size() &amp;gt; 0) {
            for(auto i : s) cout &amp;lt;&amp;lt; i &amp;lt;&amp;lt; &quot; &quot;;
        }
        else cout &amp;lt;&amp;lt; &quot;none&quot;;

        cout &amp;lt;&amp;lt; &quot;\n\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 8975번 : PJESMA&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;트리를 사용한 집합과 맵&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 단어가 주어지고, M개의 단어가 주어질 때 이 M개의 단어들을 순서대로 보면서 N개의 단어 중에 있으면 체크한다면 N개의 단어 중 절반 이상이 체크될 때 M개의 단어들 중 몇 번째 단어까지 체크해야 하는지 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 N개의 단어는 set에 저장해주고, M개의 단어들을 순서대로 확인하면서 count 해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 M개의 단어들 중에서 중복이 있기 때문에 map을 이용하여 중복이 발생하지 않도록 해주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660976944847&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    set&amp;lt;string&amp;gt; s;

    for(int i=0; i&amp;lt;N; i++) {
        string str; cin &amp;gt;&amp;gt; str;

        s.insert(str);
    }

    int M; cin &amp;gt;&amp;gt; M;

    vector&amp;lt;string&amp;gt; v(M);

    for(int i=0; i&amp;lt;M; i++) cin &amp;gt;&amp;gt; v[i];

    unordered_map&amp;lt;string, bool&amp;gt; m;
    int cnt = 0;

    for(int i=0; i&amp;lt;M; i++) {
        if(m[v[i]]) continue;

        m[v[i]] = true;

        if(s.count(v[i]) &amp;gt; 0) cnt++;

        if(cnt &amp;gt;= (N+1)/2) {
            cout &amp;lt;&amp;lt; i+1 &amp;lt;&amp;lt; &quot;\n&quot;;
            break;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 4775번 : Spelling Be&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;트리를 사용한 집합과 맵&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사전에 있는 단어들이 주어지고, 각 이메일에 대해 사전에 없는 단어들이 있으면 그 단어들을 출력하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Set을 사용하여 쉽게 풀이할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사전에 있는 단어들을 Set에 넣어주고, 각 이메일들에 대해 Set에 단어가 있는지 체크하여 없으면 벡터에 저장해준 뒤 마지막에 모두 출력해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660974717216&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    multiset&amp;lt;string&amp;gt; s;

    while(N--) {
        string str; cin &amp;gt;&amp;gt; str;

        s.insert(str);
    }

    int T; cin &amp;gt;&amp;gt; T;

    for(int t=1; t&amp;lt;=T; t++) {
        vector&amp;lt;string&amp;gt; v;

        while(true) {
            string str; cin &amp;gt;&amp;gt; str;
            if(str == &quot;-1&quot;) break;

            if(s.count(str) == 0) v.push_back(str);
        }

        if(v.size() == 0) {
            cout &amp;lt;&amp;lt; &quot;Email &quot; &amp;lt;&amp;lt; t &amp;lt;&amp;lt; &quot; is spelled correctly.\n&quot;;
        }
        else {
            cout &amp;lt;&amp;lt; &quot;Email &quot; &amp;lt;&amp;lt; t &amp;lt;&amp;lt; &quot; is not spelled correctly.\n&quot;;

            for(int i=0; i&amp;lt;v.size(); i++) cout &amp;lt;&amp;lt; v[i] &amp;lt;&amp;lt; &quot;\n&quot;;
        }
    }

    cout &amp;lt;&amp;lt; &quot;End of Output\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 5390번 : Gene Shuffle&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;트리를 사용한 집합과 맵&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N 이하의 자연수로 이루어진 두 개의 순열에 대해, 부분 원소가 같은 부분 집합을 최대한 많이 쪼개지도록 찾는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;set을 사용하여 원소를 순서대로 2개의 set에 넣어주다가 두 set이 같아질 때 그 구간을 출력해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여담으로 unordered_set을 사용해봤는데 시간 초과가 발생했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;set의 경우 탐색 시간이 O(log N)인 것에 비해 unordered_set은 O(1)일 때도 있고 최악의 경우 O(N)이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660975801783&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    while(T--) {
        int N; cin &amp;gt;&amp;gt; N;

        vector&amp;lt;int&amp;gt; v(N), u(N);

        for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];
        for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; u[i];

        int cur = 0;

        while(cur &amp;lt; N) {
            set&amp;lt;int&amp;gt; sv, su;

            for(int i=cur; i&amp;lt;N; i++) {
                sv.insert(v[i]);
                su.insert(u[i]);

                if(sv == su) {
                    cout &amp;lt;&amp;lt; cur+1 &amp;lt;&amp;lt; &quot;-&quot; &amp;lt;&amp;lt; i+1 &amp;lt;&amp;lt; &quot; &quot;;

                    cur = i+1;

                    break;
                }
            }
        }

        cout &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 15081번 : Is Everbody Appy?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;트리를 사용한 집합과 맵&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N명의 사람들이 원하는 앱의 이름들이 주어지고 (먼저 나오는 이름이 우선순위가 높은 앱), 각 사람은 한 개의 앱만을 받을 수 있으며, 먼저 나오는 사람이 우선 순위일 때 각 사람이 받아야 하는 앱의 이름을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맨 윗 사람부터 그리디하게 앞의 앱부터 set을 체크해보면서 set에 없는 이름일 경우 그 앱을 출력해주고 set에 추가해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661062292121&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    set&amp;lt;string&amp;gt; s;

    while(N--) {
        int M; cin &amp;gt;&amp;gt; M;

        vector&amp;lt;string&amp;gt; v(M);

        for(int i=0; i&amp;lt;M; i++) cin &amp;gt;&amp;gt; v[i];

        for(int i=0; i&amp;lt;M; i++) {
            if(s.count(v[i]) == 0) {
                cout &amp;lt;&amp;lt; v[i] &amp;lt;&amp;lt; &quot; &quot;;

                s.insert(v[i]);

                break;
            }
        }
    }
    cout &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 17048번 : Jarvis&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;트리를 사용한 집합과 맵&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열 A와 B가 주어질 때, A의 전체에 x를 더하여 B와 일치하는 원소 수가 최대가 되게 하려고 할 때, 최대로 일치하는 원소 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;map을 사용하여 격차(b[i] - a[i])들을 모두 저장해주고, 그들 중 빈도가 가장 높은 격차의 횟수를 답으로 얻어주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661062428753&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;int&amp;gt; v(N), u(N);

    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; u[i];

    map&amp;lt;int, int&amp;gt; m;
    vector&amp;lt;int&amp;gt; w;

    for(int i=0; i&amp;lt;N; i++) {
        if(m[u[i] - v[i]] == 0)
            w.push_back(u[i] - v[i]);

        m[u[i] - v[i]]++;
    }

    int ans = 0;

    for(int i=0; i&amp;lt;w.size(); i++) ans = max(ans, m[w[i]]);

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 18703번 : Duplicate Files&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt; Silver V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류: &lt;span style=&quot;color: #ee2323;&quot;&gt;트리를 사용한 집합과 맵&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 파일들의 이름과 번호가 주어질 때, 동일한 이름의 파일은 번호가 더 낮은 것만을 남긴다고 한다면 마지막으로 남는 파일들의 번호들을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;map을 사용하여 번호를 저장하고, 만약 번호가 없을 경우 추가해주고 번호가 있는데 새로 입력된 파일의 번호가 더 작을 경우 갱신해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661062536826&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    while(T--) {
        int N; cin &amp;gt;&amp;gt; N;

        unordered_map&amp;lt;string, int&amp;gt; m;
        vector&amp;lt;string&amp;gt; v;

        while(N--) {
            string str; cin &amp;gt;&amp;gt; str;
            int x; cin &amp;gt;&amp;gt; x;

            if(m[str] == 0) {
                m[str] = x;

                v.push_back(str);
            }
            else m[str] = min(m[str], x);
        }

        vector&amp;lt;int&amp;gt; u;

        for(int i=0; i&amp;lt;v.size(); i++) u.push_back(m[v[i]]);

        sort(u.begin(), u.end());

        for(int i=0; i&amp;lt;u.size(); i++) cout &amp;lt;&amp;lt; u[i] &amp;lt;&amp;lt; &quot; &quot;;
        cout &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 18706번 : Coffee&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;트리를 사용한 집합과 맵&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 커피의 종류와 가격(small, medium, large의 가격), M명의 이름과 원하는 커피가 주어지며, 배송료 100달러를 M명이 나눠서 지불할 때 최종적으로 각 사람이 내야 하는 가격을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(이 때 5의 배수 &amp;plusmn;1인 경우는 가까운 5의 배수로 반올림해야 한다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;map을 사용하여 문제에서 주어진 조건대로 구현하면 되는 구현 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배송료는 100 / M을 더해서 구해줄 수 있으며, 최종적으로 이 가격에 5로 나눈 나머지가 1 또는 4일 때만 추가적인 처리를 해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661062642064&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    while(T--) {
        int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

        map&amp;lt;string, int&amp;gt; ms, mm, ml;

        for(int i=0; i&amp;lt;N; i++) {
            string str; cin &amp;gt;&amp;gt; str;

            int a, b, c; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b &amp;gt;&amp;gt; c;

            ms[str] = a;
            mm[str] = b;
            ml[str] = c;
        }

        for(int i=0; i&amp;lt;M; i++) {
            string a, b, c; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b &amp;gt;&amp;gt; c;

            int ans = 0;

            if(b == &quot;small&quot;) ans += ms[c];
            else if(b == &quot;medium&quot;) ans += mm[c];
            else if(b == &quot;large&quot;) ans += ml[c];

            ans += 100 / M;

            if(ans % 5 == 1) ans--;
            else if(ans % 5 == 4) ans++;

            cout &amp;lt;&amp;lt; a &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 7847번 : Sales Report&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;트리를 사용한 집합과 맵&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 물건에 대해 2개의 고유한 id가 주어지고, 이들의 판매 수량이 주어질 때 2차원 표를 만들어 각 id에 해당하는 물건의 수의 합을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;map을 pair&amp;lt;int, int&amp;gt; &amp;rarr; int로 선언하여, 각 id 쌍에 대한 map의 값을 갱신해준 뒤, 문제에서 만들라고 하는 대로 표를 출력해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661062790141&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;int&amp;gt; v, u;
    map&amp;lt;pair&amp;lt;int, int&amp;gt;, int&amp;gt; m;

    while(N--) {
        int a, b, c; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b &amp;gt;&amp;gt; c;

        v.push_back(a);
        u.push_back(b);

        m[{a, b}] += c;
    }

    sort(v.begin(), v.end());
    sort(u.begin(), u.end());

    v.erase(unique(v.begin(), v.end()), v.end());
    u.erase(unique(u.begin(), u.end()), u.end());

    cout &amp;lt;&amp;lt; -1 &amp;lt;&amp;lt; &quot; &quot;;

    for(int i=0; i&amp;lt;v.size(); i++) cout &amp;lt;&amp;lt; v[i] &amp;lt;&amp;lt; &quot; &quot;;
    cout &amp;lt;&amp;lt; &quot;\n&quot;;

    for(int i=0; i&amp;lt;u.size(); i++) {
        cout &amp;lt;&amp;lt; u[i] &amp;lt;&amp;lt; &quot; &quot;;

        for(int j=0; j&amp;lt;v.size(); j++) cout &amp;lt;&amp;lt; m[{v[j], u[i]}] &amp;lt;&amp;lt; &quot; &quot;;
        cout &amp;lt;&amp;lt;&quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 24771번 : Un-bear-albe Zoo&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;트리를 사용한 집합과 맵&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 동물의 이름이 주어지는데 여러 단어로 이루어진 입력이고, 마지막 단어만이 동물의 종을 나타내며 이들은 대소문자가 섞여서 나올 수 있다고 할 때, 최종적으로 나온 동물들과 이들의 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;map을 사용하여 각 이름들에 대한 개수를 저장해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 동물의 이름 중간에도 대문자가 섞여 나올 수 있으므로 각 이름의 모든 문자에 대해 대문자 여부를 검사해주어 바꿔주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661062924306&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    for(int t=1; ; t++) {
        int N; cin &amp;gt;&amp;gt; N;
        if(N == 0) break;

        cin.ignore();

        map&amp;lt;string, int&amp;gt; m;
        vector&amp;lt;string&amp;gt; v;

        while(N--) {
            string str; getline(cin, str);

            string name = &quot;&quot;;

            for(int i=str.length()-1; i&amp;gt;=0; i--) {
                if(str[i] == ' ') break;

                name = str[i] + name;
            }

            for(int j=0; j&amp;lt;name.length(); j++)
                if(name[j] &amp;gt;= 'A' &amp;amp;&amp;amp; name[j] &amp;lt;= 'Z') name[j] += 'a' - 'A';

            m[name]++;
            v.push_back(name);
        }

        sort(v.begin(), v.end());
        v.erase(unique(v.begin(), v.end()), v.end());

        cout &amp;lt;&amp;lt; &quot;List &quot; &amp;lt;&amp;lt; t &amp;lt;&amp;lt; &quot;:\n&quot;;

        for(int i=0; i&amp;lt;v.size(); i++)
            cout &amp;lt;&amp;lt; v[i] &amp;lt;&amp;lt; &quot; | &quot; &amp;lt;&amp;lt; m[v[i]] &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 6851번 : Snowflakes&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;트리를 사용한 집합과 맵&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 6자리 숫자로 이루어진 배열이 주어지고, 각 배열은 뒤집거나 1칸씩 shift할 수 있다고 할 때, 이러한 이동을 거쳐 서로 같은 6자리 배열 쌍이 존재하는지를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6자리 shift와 뒤집기를 합치면 총 12개의 배열이 나타날 수 있는데, 이들을 모두 해본 뒤 사전순으로 가장 앞서는 것으로 설정한 뒤 같은 배열이 존재하는지 체크해보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661063025290&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    map&amp;lt;vector&amp;lt;int&amp;gt;, bool&amp;gt; m;
    bool check = false;

    while(N--) {
        vector&amp;lt;int&amp;gt; v(6);
        for(int i=0; i&amp;lt;6; i++) cin &amp;gt;&amp;gt; v[i];

        vector&amp;lt;int&amp;gt; w(v);

        for(int i=0; i&amp;lt;6; i++) {
            vector&amp;lt;int&amp;gt; u;

            for(int j=i; j&amp;lt;6; j++) u.push_back(w[j]);
            for(int j=0; j&amp;lt;i; j++) u.push_back(w[j]);

            v = min(v, u);
        }

        reverse(w.begin(), w.end());

        for(int i=0; i&amp;lt;6; i++) {
            vector&amp;lt;int&amp;gt; u;

            for(int j=i; j&amp;lt;6; j++) u.push_back(w[j]);
            for(int j=0; j&amp;lt;i; j++) u.push_back(w[j]);

            v = min(v, u);
        }

        if(m[v]) {
            check = true;
            break;
        }

        m[v] = true;
    }

    if(check) cout &amp;lt;&amp;lt; &quot;Twin snowflakes found.\n&quot;;
    else cout &amp;lt;&amp;lt; &quot;No two snowflakes are alike.\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 15237번 : Cipher&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;해시를 사용한 집합과 맵, 정렬&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 수가 주어질 때, 빈도가 높은 수가 먼저 나오고, 같은 빈도인 경우 먼저 나온 수가 앞에 나오도록 정렬할 때 정렬한 배열을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sort의 cmp 함수를 직접 구현하여 구현해줄 수 있고, cmp 함수에서는 map을 활용하여 return 값을 지정해줄 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;map으로 각 수의 빈도를 세어주고, 먼저 나오는 것의 여부도 map으로 최초로 나온 idx를 저장해서 확인해줄 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661063131971&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

map&amp;lt;int, int&amp;gt; m, idx;

bool cmp(int a, int b) {
    if(m[a] != m[b]) return m[a] &amp;gt; m[b];
    else return idx[a] &amp;lt; idx[b];
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    vector&amp;lt;int&amp;gt; v;

    for(int i=0; i&amp;lt;N; i++) {
        int x; cin &amp;gt;&amp;gt; x;

        if(m[x] == 0) {
            v.push_back(x);

            idx[x] = i;
        }

        m[x]++;
    }

    sort(v.begin(), v.end(), cmp);

    for(int i=0; i&amp;lt;v.size(); i++)
        for(int j=0; j&amp;lt;m[v[i]]; j++) cout &amp;lt;&amp;lt; v[i] &amp;lt;&amp;lt; &quot; &quot;;

    cout &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 22133번 : Олимпиада&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;b&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Silver I&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;포함 배제의 원리&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세 직사각형의 가로 세로가 주어질 때 합집합 넓이의 최소를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포함 배제의 원리로 풀어줄 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 세 직사각형의 넓이를 우선 다 더하고, 그 다음 두 직사각형의 겹치는 넓이를 빼주고 (3C2 3쌍), 마지막으로 세 직사각형이 모두 겹치는 넓이를 더해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660975832636&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    while(true) {
        int a, b, c, d, e, f; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b &amp;gt;&amp;gt; c &amp;gt;&amp;gt; d &amp;gt;&amp;gt; e &amp;gt;&amp;gt; f;
        if(a*a + b*b + c*c + d*d + e*e + f*f == 0) break;

        if(a &amp;lt; b) swap(a, b);
        if(c &amp;lt; d) swap(c, d);
        if(e &amp;lt; f) swap(e, f);

        int ans = a*b + c*d + e*f;

        ans -= min(a, c) * min(b, d);
        ans -= min(c, e) * min(d, f);
        ans -= min(e, a) * min(f, b);

        ans += min({a, c, e}) * min({b, d, f});

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 7121번 : Pencil Factory&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Silver IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;포함 배제의 원리&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Painting은 N개의 o 이후에 x가 1개씩 나오고, Varnishing은 M개의 o 이후에 x가 1개씩 나온다고 할 때, 1 ~ K 중에서 다음의 4가지를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Painting과 Varnishing이 모두 o인 것의 개수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 둘 다 x인 것의 개수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. Painting만 o인 것의 개수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. Varnishing만 o인 것의 개수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 N과 M의 최소공배수를 구한 뒤, 포함과 배제의 원리를 이용하여 풀이할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 참고하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660975832637&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M, K; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M &amp;gt;&amp;gt; K;

    N++, M++;

    int lcm = N * M / __gcd(N, M);

    cout &amp;lt;&amp;lt; K - K/N - K/M + K/lcm &amp;lt;&amp;lt; &quot; &quot;;
    cout &amp;lt;&amp;lt; K/lcm &amp;lt;&amp;lt; &quot; &quot;;
    cout &amp;lt;&amp;lt; K/M - K/lcm &amp;lt;&amp;lt; &quot; &quot;;
    cout &amp;lt;&amp;lt; K/N - K/lcm &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/알고리즘 공부 내용 정리</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/613</guid>
      <comments>https://restudycafe.tistory.com/613#entry613comment</comments>
      <pubDate>Sat, 20 Aug 2022 12:36:58 +0900</pubDate>
    </item>
    <item>
      <title>백준 BOJ 스위핑, 값/좌표 압축 알고리즘 문제 풀이 모음 220819</title>
      <link>https://restudycafe.tistory.com/612</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 18869번 : 멀티버스 II&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;값/좌표 압축&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 집합에 대해, a_i, a_j와 b_i, b_j의 대소 관계가 모두 같다면 두 집합은 동일하다고 할 때, N개의 집합에 대해 몇 개의 집합 쌍이 동일한지를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 집합에 대해 좌표 압축을 수행해주면, 원소들의 대소 관계가 같은 집합은 동일한 원소들을 가지게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 활용하여 좌표 압축을 N번 반복해준 뒤 브루트포스로 답을 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660896726103&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int M, N; cin &amp;gt;&amp;gt; M &amp;gt;&amp;gt; N;

    vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; v(M, vector&amp;lt;int&amp;gt;(N)), u(v), w(v);

    for(int i=0; i&amp;lt;M; i++) {
        for(int j=0; j&amp;lt;N; j++) {
            cin &amp;gt;&amp;gt; v[i][j];
            u[i][j] = v[i][j];
            }

        sort(u[i].begin(), u[i].end());
        u[i].erase(unique(u[i].begin(), u[i].end()), u[i].end());

        for(int j=0; j&amp;lt;v[i].size(); j++)
            w[i][j] = lower_bound(u[i].begin(), u[i].end(), v[i][j]) - u[i].begin();
    }

    int ans = 0;

    for(int i=0; i&amp;lt;M; i++)
        for(int j=i+1; j&amp;lt;M; j++)
            if(w[i] == w[j]) ans++;

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 1911번 : 흙길 보수하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;그리디, 스위핑&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1차원 좌표 상의 N개의 물 웅덩이의 양 끝 좌표가 주어질 때, 길이가 M인 널빤지로 이들을 모두 커버하기 위해서 최소 몇 개의 널빤지가 필요한지 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 N개의 웅덩이를 좌표 순으로 정렬한 뒤, 왼쪽 웅덩이부터 최소한의 판자로 메꾸고 나서 현재 좌표를 판자의 오른쪽 끝으로 갱신해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 웅덩이에 대해서는, 웅덩이의 오른쪽 끝보다 현재 좌표가 크면 그냥 넘어가고, 그렇지 않으면 오른쪽 끝까지 다시 판자로 덮는 과정을 반복한다. (스위핑)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660881653671&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    vector&amp;lt;pair&amp;lt;int, int&amp;gt;&amp;gt; v(N);
    for(int i=0; i&amp;lt;N; i++)
        cin &amp;gt;&amp;gt; v[i].first &amp;gt;&amp;gt; v[i].second;

    sort(v.begin(), v.end());

    int x = INT_MIN, ans = 0;

    for(int i=0; i&amp;lt;N; i++) {
        if(x &amp;gt;= v[i].second) continue;

        x = max(x, v[i].first);

        int cnt = ((v[i].second - x) - 1) / M + 1;

        ans += cnt;
        x += M * cnt;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 21600번 : 계단&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;그리디, 스위핑&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 막대로 이루어진 히스토그램이 주어졌을 때, 가장 큰 연속된 계단의 크기를 구하는 문제이다. (자세한 설명은 문제 원문을 참고하는 것을 추천한다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cur를 현재 위치를 마지막으로 이루는 계단의 높이라고 하고, ans를 지금까지 cur 중에 최대 cur 값이라고 하면, 맨 왼쪽 값부터 입력을 받으면서 cur와 ans를 갱신해나가며 답을 구할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 특정 위치에서의 높이가 cur보다 높다면, cur를 1 증가시켜줄 수 있다. (1칸 더 높은 계단을 연결할 수 있으므로)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 그렇지 않다면, 현재 높이가 현재 위치를 마지막으로 하는 계단의 높이가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ans 값은 조건문에 관계없이 항상 갱신시켜주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660883864969&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    int ans = 0, cur = 0;

    for(int i=0; i&amp;lt;N; i++) {
        int x; cin &amp;gt;&amp;gt; x;

        if(x &amp;gt; cur) cur++;
        else cur = x;

        ans = max(ans, cur);
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 12867번 : N차원 여행&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;값/좌표 압축&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N차원 좌표 상에서, 원점에서 시작하여 N번의 이동을 할 때 중복 방문한 지점이 있었는지를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때, N은 10억 이하이고 이동 횟수는 50 이하이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N이 아주 크므로 좌표 압축을 통해 0인 부분을 제거하면 벡터의 크기를 50 이하로 줄일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좌표 압축을 사용해준 뒤 vector&amp;lt;int&amp;gt;에서 bool로 가는 map을 활용하여 중복 여부를 체크해줄 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660895730948&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int M, N; cin &amp;gt;&amp;gt; M &amp;gt;&amp;gt; N;

    vector&amp;lt;int&amp;gt; v(N), u(N);
    for(int i=0; i&amp;lt;N; i++) {
        cin &amp;gt;&amp;gt; v[i];
        u[i] = v[i];
    }

    vector&amp;lt;char&amp;gt; vv(N);
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; vv[i];

    sort(u.begin(), u.end());
    u.erase(unique(u.begin(), u.end()), u.end());

    vector&amp;lt;int&amp;gt; w(N);
    for(int i=0; i&amp;lt;v.size(); i++)
        w[i] = lower_bound(u.begin(), u.end(), v[i]) - u.begin();

    map&amp;lt;vector&amp;lt;int&amp;gt;, bool&amp;gt; m;
    vector&amp;lt;int&amp;gt; uu(N);
    m[uu] = true;

    bool check = true;

    for(int i=0; i&amp;lt;N; i++) {
        if(vv[i] == '+') uu[w[i]]++;
        else if(vv[i] == '-') uu[w[i]]--;

        if(m[uu]) check = false;

        m[uu] = true;
    }

    if(check) cout &amp;lt;&amp;lt; 1 &amp;lt;&amp;lt; &quot;\n&quot;;
    else cout &amp;lt;&amp;lt; 0 &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 15889번 : 호 안에 수류탄이야!!&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;그리디, 스위핑&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N명의 사람의 수직선 상의 좌표가 주어지고, 그 중 왼쪽 N-1명이 수류탄을 던질 수 있는 범위가 주어질 때, 맨 왼쪽 사람에서 전달을 시작하여 맨 오른쪽 사람이 받을 수 있는지의 여부를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맨 왼쪽 사람부터 시작하여 각 사람이 도달 가능한 최대 거리를 구하고, 다음 사람이 이 최대 거리 내에 있어야 전달이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 한 사람이라도 해당하지 않는 경우가 발생한다면 맨 오른쪽까지 도달하는 것은 불가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래는 이 문제에서는 정렬을 해줄 필요가 없다고 나오지는 않았으나, 맥락 상 좌표 순서대로 주어진다고 유추가 가능하기 때문에 정렬을 해주지 않아도 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660880831170&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;int&amp;gt; v(N);
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];

    vector&amp;lt;int&amp;gt; u(N-1);
    for(int i=0; i&amp;lt;N-1; i++) cin &amp;gt;&amp;gt; u[i];

    int sum = 0;

    for(int i=0; i&amp;lt;N-1; i++) {
        sum = max(sum, v[i] + u[i]);

        if(sum &amp;lt; v[i+1]) {
            cout &amp;lt;&amp;lt; &quot;엄마 나 전역 늦어질 것 같아\n&quot;;
            return 0;
        }
    }

    cout &amp;lt;&amp;lt; &quot;권병장님, 중대장님이 찾으십니다\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 24035번 : Impartial Offerings&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;값/좌표 압축&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N마리의 강아지들에게 간식을 주는데, 모든 강아지들에게 간식을 1 이상 주되 무게가 더 무거운 강아지한테는 더 많은 간식을 준다고 할 때 주어야 할 모든 간식의 양의 최솟값을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;강아지들의 무게에 대한 값들을 압축해주면, 그 합들이 답이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 N = 4이고 30 20 5 5라면, 이를 값 압축을 해주면 3 2 1 1이 되고, 간식을 이렇게 주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 이 경우 답은 3+2+1+1 = 7이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660885409873&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    for(int t=1; t&amp;lt;=T; t++) {
        int N; cin &amp;gt;&amp;gt; N;

        vector&amp;lt;int&amp;gt; v(N), u(N);
        for(int i=0; i&amp;lt;N; i++) {
            cin &amp;gt;&amp;gt; v[i];
            u[i] = v[i];
        }

        sort(u.begin(), u.end());
        u.erase(unique(u.begin(), u.end()), u.end());

        vector&amp;lt;int&amp;gt; w(N);
        for(int i=0; i&amp;lt;v.size(); i++)
            w[i] = lower_bound(u.begin(), u.end(), v[i]) - u.begin() + 1;

        int ans = 0;

        for(int i=0; i&amp;lt;N; i++) ans += w[i];

        cout &amp;lt;&amp;lt; &quot;Case #&quot; &amp;lt;&amp;lt; t &amp;lt;&amp;lt; &quot;: &quot; &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 8641번 : Sklep&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;해시를 사용한 집합과 맵&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 목록에 걸쳐 상품의 번호와 개수가 주어질 때, 상품의 번호가 한 번씩 나타나도록 하여 각 상품의 개수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 출력 순서는 해당 상품 번호가 먼저 나타난 순으로 출력해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해시를 사용한 집합과 맵을 사용하여 풀이해줄 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전에 나온 적 없는 상품이면 벡터에 넣어주고, 마지막에 이 벡터에 나온 순서대로 맵의 값을 출력해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;unordered_map을 사용하면 일반 map보다 2배 빠른 속도로 통과할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660892771200&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;int&amp;gt; v;
    unordered_map&amp;lt;int, int&amp;gt; m;

    while(N--) {
        int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

        if(m[a] == 0) v.push_back(a);

        m[a] += b;
    }

    cout &amp;lt;&amp;lt; v.size() &amp;lt;&amp;lt; &quot;\n&quot;;

    for(int i=0; i&amp;lt;v.size(); i++)
        cout &amp;lt;&amp;lt; v[i] &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; m[v[i]] &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 18881번 : Social Distancing II&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;정렬, 스위핑&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N마리의 소가 있고, 각각 위치와 병에 걸린 여부(1 or 0)가 주어질 때 병 걸린 소는 특정 거리 (입력으로 주어지지 않음) 내에 있는 소들을 감염시킨다고 할 때, 최초에 감염되었을 수 있는 소의 최소 마리 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 소들을 정렬해주고, 인접한 두 소들 중 한 마리만 병에 걸린 경우 감염 반경은 그 두 소의 거리 미만임을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 모든 인접한 소들에 대해 이러한 검사를 해주어 r의 범위를 찾는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 병에 걸린 소들만 벡터에 저장한 뒤 인접한 소들 사이의 거리가 r보다 큰 경우 이들은 서로 다른 근원지에서 병이 걸렸음을 알 수 있으므로, 인접한 병 걸린 소들을 탐색하며 답에 1씩 추가해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660869406865&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;pair&amp;lt;int, int&amp;gt;&amp;gt; v(N);

    for(int i=0; i&amp;lt;N; i++)
        cin &amp;gt;&amp;gt; v[i].first &amp;gt;&amp;gt; v[i].second;

    sort(v.begin(), v.end());

    int r = INT_MAX;

    for(int i=1; i&amp;lt;N; i++)
        if(v[i-1].second != v[i].second)
            r = min(r, v[i].first - v[i-1].first - 1);

    vector&amp;lt;int&amp;gt; u;

    for(int i=0; i&amp;lt;N; i++)
        if(v[i].second == 1) u.push_back(v[i].first);

    int ans = 1;

    for(int i=1; i&amp;lt;u.size(); i++)
        if(u[i] - u[i-1] &amp;gt; r) ans++;

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 14567번 : 선수과목 (Prerequisite)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;위상 정렬&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;M개의 순서쌍 (a, b)에 대해 a를 반드시 b보다 이전 학기에 들어야할 때, N개의 과목을 최소 학기에 모두 듣기 위해서는 각 과목들을 몇 학기에 들어야 하는지 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위상 정렬 문제로, 기존 위상 정렬 코드에서 queue 부분에 학기만 기록할 수 있도록 해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최초로 queue에 넣은 과목들은 1학기에 듣고, 그 다음 push 되는 것들은 1학기 증가시켜서 저장하고, ... 이 과정을 반복하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660884117027&quot; class=&quot;arduino&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj(N+1);
    vector&amp;lt;int&amp;gt; deg(N+1);

    while(M--) {
        int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

        adj[a].push_back(b);

        deg[b]++;
    }

    queue&amp;lt;int&amp;gt; q;
    vector&amp;lt;int&amp;gt; ans(N+1);

    for(int i=1; i&amp;lt;=N; i++)
        if(deg[i] == 0) {
            q.push(i);

            ans[i] = 1;
        }

    while(!q.empty()) {
        int x = q.front();
        q.pop();

        for(int i=0; i&amp;lt;adj[x].size(); i++) {
            int y = adj[x][i];

            deg[y]--;

            if(deg[y] == 0) {
                ans[y] = ans[x] + 1;
                q.push(y);
            }
        }
    }

    for(int i=1; i&amp;lt;=N; i++) cout &amp;lt;&amp;lt; ans[i] &amp;lt;&amp;lt; &quot; &quot;;
    cout &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 2171번 : 직사각형의 개수&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;자료 구조&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2차원 좌표 평면 상에 주어진 N개의 점에 대해, 그들 중 4개를 선택하여 만들 수 있는 직사각형의 개수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래는 좌표 압축을 사용하여 풀이하려고 했는데, 더 좋은 풀이 겸 배울 게 많은 방법이 있어서 해당 방법으로 풀이해보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;set을 사용하면 log 시간에 데이터를 삽입, 삭제, 탐색할 수 있기 때문에 이런 문제를 짧은 코드로도 풀이할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무튼 핵심 풀이는 set에 모든 좌표들을 넣고, 2중 for문으로 잡은 두 점을 직사각형의 대각선에 위치한 점이라고 보고 set에 나머지 두 점이 존재하는지를 찾는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 이 경우 반대 대각선으로도 직사각형의 count가 한 번 더 일어나므로, count 된 값을 2로 나누어 정답을 얻어주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660903952072&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;pair&amp;lt;int, int&amp;gt;&amp;gt; v;
    set&amp;lt;pair&amp;lt;int, int&amp;gt;&amp;gt; s;

    for(int i=0; i&amp;lt;N; i++) {
        int x, y; cin &amp;gt;&amp;gt; x &amp;gt;&amp;gt; y;

        v.push_back({x, y});
        s.insert({x, y});
    }

    int ans = 0;

    for(int i=0; i&amp;lt;N; i++)
        for(int j=i+1; j&amp;lt;N; j++) {
            if(v[i].first == v[j].first || v[i].second == v[j].second) continue;

            if(s.count({v[i].first, v[j].second}) &amp;gt; 0 &amp;amp;&amp;amp; s.count({v[j].first, v[i].second})) ans++;
        }

    ans /= 2;

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 11830번 : Star triangles&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;해시를 사용한 집합과 맵&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 점의 좌표가 주어졌을 때, 그 중 3개를 선택하여 두 변이 x축, y축과 평행한 직각삼각형의 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 점의 좌표에 대해서, x 좌표가 같은 점 1개와 y 좌표가 같은 점 1개를 선택해서 직각삼각형을 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 map 2개를 선언하여 각 점들의 x 좌표와 y 좌표의 수를 저장하고, 각 점에 대해 위에서 말한대로 점 한 개씩을 선택해서 곱해주면 경우의 수가 된다. (물론 자기 자신에 해당하는 점 1개는 빼야한다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660905646595&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;pair&amp;lt;int, int&amp;gt;&amp;gt; v;
    unordered_map&amp;lt;int, int&amp;gt; mx, my;

    for(int i=0; i&amp;lt;N; i++) {
        int x, y; cin &amp;gt;&amp;gt; x &amp;gt;&amp;gt; y;

        v.push_back({x, y});

        mx[x]++;
        my[y]++;
    }

    int ans = 0;

    for(int i=0; i&amp;lt;N; i++) {
        ans += (mx[v[i].first] - 1) * (my[v[i].second] - 1);
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 5971번 : Meeting Place&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;LCA&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 노드를 가진 트리가 주어지고 M개의 쿼리에 대해 두 노드의 최소 공통 조상(LCA)을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N이 1,000 이하이므로 하나의 쿼리를 O(H) 시간에 처리하는 풀이로 풀어도 되지만, log(H) 시간 LCA 알고리즘을 다시 작성해보는 겸 로그 시간 풀이로 풀이하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660914850218&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj, par, dis;
vector&amp;lt;int&amp;gt; dep;

void fp(int p, int x, int d) {
    if(adj[x].size() == 0) return;

    par[x][0] = p;
    dep[x] = d;

    for(int i=0; i&amp;lt;adj[x].size(); i++) {
        int y = adj[x][i];

        if(y != p) fp(x, y, d+1);
    }
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    adj.resize(N+1);

    for(int i=2; i&amp;lt;=N; i++) {
        int x; cin &amp;gt;&amp;gt; x;

        adj[i].push_back(x);
        adj[x].push_back(i);
    }

    par.resize(N+1, vector&amp;lt;int&amp;gt;(30));
    dep.resize(N+1);

    fp(0, 1, 0);

    int H = (int)floor(log2(N+1));

    dis.resize(N+1, vector&amp;lt;int&amp;gt;(30));

    for(int i=1; i&amp;lt;=H; i++)
        for(int j=2; j&amp;lt;=N; j++)
            if(par[j][i-1] != 0) {
                par[j][i] = par[par[j][i-1]][i-1];
                dis[j][i] = dis[j][i-1] + dis[par[j][i-1]][i-1];
            }

    while(M--) {
        int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

        if(dep[a] != dep[b]) {
            if(dep[a] &amp;lt; dep[b]) swap(a, b);

            int diff = dep[a] - dep[b];

            for(int i=0; diff&amp;gt;0; i++) {
                if(diff % 2 == 1) a = par[a][i];

                diff /= 2;
            }
        }

        if(a != b) {
            for(int i=H; i&amp;gt;=0; i--)
                if(par[a][i] != 0 &amp;amp;&amp;amp; par[a][i] != par[b][i]) {
                    a = par[a][i];
                    b = par[b][i];
                }

            a = par[a][0];
        }

        cout &amp;lt;&amp;lt; a &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/알고리즘 공부 내용 정리</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/612</guid>
      <comments>https://restudycafe.tistory.com/612#entry612comment</comments>
      <pubDate>Fri, 19 Aug 2022 00:11:20 +0900</pubDate>
    </item>
    <item>
      <title>백준 BOJ 문제 풀이 모음 : 그래프와 인접 행렬의 활용 220818</title>
      <link>https://restudycafe.tistory.com/611</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 17272번 : 리그 오브 레전설 (Large)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N초를 길이가 1초인 스킬과 길이가 M초인 스킬로 구성하는 방법의 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dp[N] = dp[N-1] + dp[N-M]이라는 점화식을 세울 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 Large 문제에서는 N이 10^18 이하이므로 dp로는 풀이가 불가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 점화식을 행렬로 구성하여 행렬의 거듭제곱으로 답을 구해주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1509&quot; data-origin-height=&quot;1729&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IYB7k/btrJ1DeQEO8/YtlKCBPsQ3qIIOcxpqPUE1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IYB7k/btrJ1DeQEO8/YtlKCBPsQ3qIIOcxpqPUE1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IYB7k/btrJ1DeQEO8/YtlKCBPsQ3qIIOcxpqPUE1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIYB7k%2FbtrJ1DeQEO8%2FYtlKCBPsQ3qIIOcxpqPUE1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;639&quot; height=&quot;732&quot; data-origin-width=&quot;1509&quot; data-origin-height=&quot;1729&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 점화식을 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 M이 100 이하이므로, 행렬의 크기는 아무리 커도 100 x 100을 넘어가지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 A 행렬을 N 제곱 해주면, 곱해지는 행렬은 a_0, a_-1, ...으로 구성되는데, 정의에 의해 a_0 = 1이고 그 외에는 0이다. (상식적으로 생각해보면 된다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 a_N은 A^N의 0행 0열 원소가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660796202825&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

typedef vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; mat;
int N, ex, mod = 1e9 + 7;

mat f(mat&amp;amp; v, mat&amp;amp; u) {
    mat w(N, vector&amp;lt;int&amp;gt;(N));

    for(int i=0; i&amp;lt;N; i++)
        for(int j=0; j&amp;lt;N; j++)
            for(int k=0; k&amp;lt;N; k++)
                w[i][j] = (w[i][j] + v[i][k] * u[k][j]) % mod;

    return w;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    cin &amp;gt;&amp;gt; ex &amp;gt;&amp;gt; N;

    mat ba(N, vector&amp;lt;int&amp;gt;(N));

    ba[0][0] = ba[0][N-1] = 1;

    for(int i=1; i&amp;lt;N; i++) ba[i][i-1] = 1;

    mat v(N, vector&amp;lt;int&amp;gt;(N));
    for(int i=0; i&amp;lt;N; i++) v[i][i] = 1;

    while(ex &amp;gt; 0) {
        if(ex % 2 == 1) v = f(v, ba);

        ba = f(ba, ba);
        ex /= 2;
    }

    cout &amp;lt;&amp;lt; v[0][0] &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 이 문제의 풀이와 같은 풀이로 &lt;b&gt;백준 BOJ 17271번 : 리그 오브 레전설 (Small)&lt;/b&gt;을 풀이할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 19587번 : 객실 배치&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 층에 2호까지 있는 N층의 객실들에 대해, 위 아래 또는 1, 2호 모두에 손님이 있지 않도록 배치하는 경우의 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;2768&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AE18o/btrJXSdoTsS/9bPBcjEuyC7evnJTZqgwQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AE18o/btrJXSdoTsS/9bPBcjEuyC7evnJTZqgwQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AE18o/btrJXSdoTsS/9bPBcjEuyC7evnJTZqgwQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAE18o%2FbtrJXSdoTsS%2F9bPBcjEuyC7evnJTZqgwQ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;584&quot; height=&quot;1010&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;2768&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 층의 객실 배치를 0, 1, 2의 세 가지로 나누어 점화식을 세워보면 위와 같이 되고, 이는 행렬로 나타낼 수 있으며 N-1 제곱을 하여 모든 원소의 합을 통해 경우의 수를 구할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;행렬의 log 시간 거듭 제곱을 구현하여 답을 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660800860583&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

typedef vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; mat;
int N = 3, ex, mod = 1e9 + 7;

mat f(mat&amp;amp; v, mat&amp;amp; u) {
    mat w(N, vector&amp;lt;int&amp;gt;(N));

    for(int i=0; i&amp;lt;N; i++)
        for(int j=0; j&amp;lt;N; j++)
            for(int k=0; k&amp;lt;N; k++)
                w[i][j] = (w[i][j] + v[i][k] * u[k][j]) % mod;

    return w;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    cin &amp;gt;&amp;gt; ex;

    mat ba(N, vector&amp;lt;int&amp;gt;(N));

    ba = {{1, 1, 1},
          {1, 0, 1},
          {1, 1, 0}};

    mat v(N, vector&amp;lt;int&amp;gt;(N));
    for(int i=0; i&amp;lt;N; i++) v[i][i] = 1;

    ex--;

    while(ex &amp;gt; 0) {
        if(ex % 2 == 1) v = f(v, ba);

        ba = f(ba, ba);
        ex /= 2;
    }

    int ans = 0;

    for(int i=0; i&amp;lt;N; i++)
        for(int j=0; j&amp;lt;N; j++) ans = (ans + v[i][j]) % mod;

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 16467번 : 병아리의 변신은 무죄&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 병아리는 매일 알을 하나씩 낳고, 각 알은 K일 후에 병아리가 된다고 할 때, N일 후 병아리의 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;점화식을 세워보면 dp[i] = dp[i-1] + dp[i-1-K]이다. (dp[0] = 1, dp[i] (i &amp;lt; 0) = 0)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 나머지는 위의 백준 BOJ 17272번 문제와 똑같이 풀어주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주의할 점은 mod 값이 1e9 + 7이 아닌 1e8 + 7이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660805755600&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

typedef vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; mat;
int N, ex, mod = 1e8 + 7;

mat f(mat&amp;amp; v, mat&amp;amp; u) {
    mat w(N, vector&amp;lt;int&amp;gt;(N));

    for(int i=0; i&amp;lt;N; i++)
        for(int j=0; j&amp;lt;N; j++)
            for(int k=0; k&amp;lt;N; k++)
                w[i][j] = (w[i][j] + v[i][k] * u[k][j]) % mod;

    return w;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    while(T--) {
        cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; ex;

        N++;

        mat ba(N, vector&amp;lt;int&amp;gt;(N));

        ba[0][0]++;
        ba[0][N-1]++;

        for(int i=1; i&amp;lt;N; i++) ba[i][i-1]++;

        mat v(N, vector&amp;lt;int&amp;gt;(N));
        for(int i=0; i&amp;lt;N; i++) v[i][i] = 1;

        while(ex &amp;gt; 0) {
            if(ex % 2 == 1) v = f(v, ba);

            ba = f(ba, ba);
            ex /= 2;
        }

        cout &amp;lt;&amp;lt; v[0][0] &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 23819번 : 묻고 더블로 마셔&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1~k번째 사람이 각자 마실 양이 주어지고, k+1번째부터 N번째 사람까지는 i-1, i-2, ..., i-k번째 사람이 마신 양을 합친 것을 P로 나눈 값을 마신다고 할 때 N번째 사람이 마시는 양을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맨 위에서 풀이한 문제와 비슷한 방식으로 풀이할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 심지어 a_1 ~ a_k 값을 모두 주기 때문에 예외 처리가 어렵지 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1421&quot; data-origin-height=&quot;1265&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ceO30J/btrJXS6aVFX/pwGLMnAaO5WhzY1phwmkKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ceO30J/btrJXS6aVFX/pwGLMnAaO5WhzY1phwmkKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ceO30J/btrJXS6aVFX/pwGLMnAaO5WhzY1phwmkKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FceO30J%2FbtrJXS6aVFX%2FpwGLMnAaO5WhzY1phwmkKK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;768&quot; height=&quot;684&quot; data-origin-width=&quot;1421&quot; data-origin-height=&quot;1265&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 2099번 : The game of death&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N명이 각자 2명의 사람을 지목하고, a번째 사람에서 시작해서 가리키는 사람을 K번 따라갔을 때 b번째 사람으로 도달하는 경우가 있는지를 판별하는 쿼리를 M개 처리하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인접 행렬을 이용하여 풀이할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 a번 사람이 b번 사람을 가리킨다면, ba[a][b] = 1로 설정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 이 행렬을 K번 거듭제곱 해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 수가 매우 커질 수 있으므로 값을 더해주지는 말고 0보다 큰 경우는 1로 처리해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;K번 거듭제곱 이후 ba[a][b] = 1이면 a에서 K번 이동하여 b로 이동이 가능한 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660789314084&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

typedef vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; mat;
int N, M, K, ex;

mat f(mat&amp;amp; v, mat&amp;amp; u) {
    mat w(N, vector&amp;lt;int&amp;gt;(N));

    for(int i=0; i&amp;lt;N; i++)
        for(int j=0; j&amp;lt;N; j++)
            for(int k=0; k&amp;lt;N; k++)
                if(v[i][k] == 1 &amp;amp;&amp;amp; u[k][j] == 1) w[i][j] = 1;

    return w;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; K &amp;gt;&amp;gt; M;

    mat ba(N, vector&amp;lt;int&amp;gt;(N));

    for(int i=0; i&amp;lt;N; i++) {
        int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

        ba[i][a-1] = ba[i][b-1] = 1;
    }

    mat v(N, vector&amp;lt;int&amp;gt;(N));
    for(int i=0; i&amp;lt;N; i++) v[i][i] = 1;

    ex = K;

    while(ex &amp;gt; 0) {
        if(ex % 2 == 1) v = f(v, ba);

        ba = f(ba, ba);
        ex /= 2;
    }

    while(M--) {
        int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

        if(v[a-1][b-1] &amp;gt; 0) cout &amp;lt;&amp;lt; &quot;death\n&quot;;
        else cout &amp;lt;&amp;lt; &quot;life\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 11767번 : Squawk Virus&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;그래프 이론, 분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래프가 주어지고, 바이러스가 처음에 K번 노드에 1개 생성되며 바이러스 1개는 1초마다 인접한 칸들로 모두 복사된다고 할 때, t초 후 총 바이러스의 개수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;K번 노드에서 t번 이동을 거쳐 도달할 수 있는 모든 경로의 수를 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 문제와 비슷하게 인접 행렬 세팅을 하여 t번 거듭제곱 해준 뒤, v[K][i]들의 합을 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660791488658&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

typedef vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; mat;
int N, M, K, ex;

mat f(mat&amp;amp; v, mat&amp;amp; u) {
    mat w(N, vector&amp;lt;int&amp;gt;(N));

    for(int i=0; i&amp;lt;N; i++)
        for(int j=0; j&amp;lt;N; j++)
            for(int k=0; k&amp;lt;N; k++) w[i][j] += v[i][k] * u[k][j];

    return w;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M &amp;gt;&amp;gt; K &amp;gt;&amp;gt; ex;

    mat ba(N, vector&amp;lt;int&amp;gt;(N));

    while(M--) {
        int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

        ba[a][b] = ba[b][a] = 1;
    }

    mat v(N, vector&amp;lt;int&amp;gt;(N));
    for(int i=0; i&amp;lt;N; i++) v[i][i] = 1;

    while(ex &amp;gt; 0) {
        if(ex % 2 == 1) v = f(v, ba);

        ba = f(ba, ba);
        ex /= 2;
    }

    int ans = 0;

    for(int i=0; i&amp;lt;N; i++) ans += v[K][i];

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 12916번 : K-Path&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N x N 크기의 인접 행렬이 주어질 때, 길이가 M인 경로의 개수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인접 행렬을 M번 거듭제곱하여 나타나는 모든 원소의 합을 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원리는 위의 문제들과 동일하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660792228151&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

typedef vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; mat;
int N, ex, mod = 1e9 + 7;

mat f(mat&amp;amp; v, mat&amp;amp; u) {
    mat w(N, vector&amp;lt;int&amp;gt;(N));

    for(int i=0; i&amp;lt;N; i++)
        for(int j=0; j&amp;lt;N; j++)
            for(int k=0; k&amp;lt;N; k++)
                w[i][j] = (w[i][j] + v[i][k] * u[k][j]) % mod;

    return w;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; ex;

    mat ba(N, vector&amp;lt;int&amp;gt;(N));

    for(int i=0; i&amp;lt;N; i++)
        for(int j=0; j&amp;lt;N; j++) cin &amp;gt;&amp;gt; ba[i][j];

    mat v(N, vector&amp;lt;int&amp;gt;(N));
    for(int i=0; i&amp;lt;N; i++) v[i][i] = 1;

    while(ex &amp;gt; 0) {
        if(ex % 2 == 1) v = f(v, ba);

        ba = f(ba, ba);
        ex /= 2;
    }

    int ans = 0;

    for(int i=0; i&amp;lt;N; i++)
        for(int j=0; j&amp;lt;N; j++) ans = (ans + v[i][j]) % mod;

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 24731번 : XOR-ABC&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N자리 이진수 a, b, c에 대해 1 &amp;le; a &amp;lt; b &amp;lt; c &amp;le; 2^N - 1이고 A ^ B = C인 (A, B, C) 순서쌍의 개수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내키는 방법은 아니지만 정 풀이가 어려우면 완전 탐색으로 작은 N 이하에 대해 수열을 구해보고, 규칙을 찾는 방법이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;623&quot; data-origin-height=&quot;639&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mfQtj/btrJ29L225N/kHclY6aQv3Sd1uGgPWJvI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mfQtj/btrJ29L225N/kHclY6aQv3Sd1uGgPWJvI0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mfQtj/btrJ29L225N/kHclY6aQv3Sd1uGgPWJvI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmfQtj%2FbtrJ29L225N%2FkHclY6aQv3Sd1uGgPWJvI0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;471&quot; height=&quot;483&quot; data-origin-width=&quot;623&quot; data-origin-height=&quot;639&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 돌려보면 0, 1, 7, 35, 155, ...의 수열이 얻어진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;규칙을 직접 찾아도 되고 OEIS를 이용해도 되는데, 아무튼 f(N) = (2^n - 1) x (2^(n-1) - 1) / 3이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 분할 정복을 이용한 거듭제곱과 페르마의 소정리를 이용해서 풀어주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정석적인 풀이는 잘 모르겠는데, 다시 풀게 되면 정리하겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660832150206&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    int a = 1, ba = 2, ex = N, mod = 1e6 + 3;

    while(ex &amp;gt; 0) {
        if(ex % 2 == 1) a = (a * ba) % mod;

        ba = (ba * ba) % mod;
        ex /= 2;
    }

    int b = 1; ba = 2, ex = N-1;

    while(ex &amp;gt; 0) {
        if(ex % 2 == 1) b = (b * ba) % mod;

        ba = (ba * ba) % mod;
        ex /= 2;
    }

    int ans = ((a - 1) * (b - 1)) % mod;

    ba = 3, ex = mod - 2;

    while(ex &amp;gt; 0) {
        if(ex % 2 == 1) ans = (ans * ba) % mod;

        ba = (ba * ba) % mod;
        ex /= 2;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 11440번 : 피보나치 수의 제곱의 합&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주어진 N에 대해 0번째 피보나치 수부터 N번째 피보나치 수의 합을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 N은 10^18 이하이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;10^18 이하인 N에 대해 N번째 피보나치 수는 O(log N) 시간에 구할 수 있지만, 피보나치 수의 제곱의 합을 구하기 위해 각 항을 일일이 구하게 되면 N log N 시간이 걸려 당연히 시간 초과이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 수열을 가지고 규칙성을 찾아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래의 코드를 돌려 N = 10 이하에서의 수열을 확인해보자. (정답 코드 아님)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660832840114&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;int&amp;gt; v(N+1);
    v[1] = 1;

    for(int i=2; i&amp;lt;=N; i++) v[i] = v[i-1] + v[i-2];

    int sum = 0;

    for(int i=1; i&amp;lt;=N; i++) {
        sum += v[i] * v[i];

        cout &amp;lt;&amp;lt; i &amp;lt;&amp;lt; &quot; : &quot; &amp;lt;&amp;lt; sum &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행시켜보면 결과는 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;477&quot; data-origin-height=&quot;331&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5NQf2/btrJ3uJdcpu/dZbyaJXtGcyPA0LPXAYBk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5NQf2/btrJ3uJdcpu/dZbyaJXtGcyPA0LPXAYBk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5NQf2/btrJ3uJdcpu/dZbyaJXtGcyPA0LPXAYBk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5NQf2%2FbtrJ3uJdcpu%2FdZbyaJXtGcyPA0LPXAYBk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;477&quot; height=&quot;331&quot; data-origin-width=&quot;477&quot; data-origin-height=&quot;331&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;규칙을 찾아보면, &lt;span style=&quot;color: #ee2323;&quot;&gt;i번째 피보나치 수를 g(i)라고 했을 때 f(N) = g(N) x g(N+1)&lt;/span&gt;임을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 두 피보나치 수를 분할 정복을 이용한 거듭제곱으로 구해서 곱해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660833143081&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

typedef vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; mat;
int mod = 1e9 + 7;

mat f(mat&amp;amp; v, mat&amp;amp; u) {
    int N = 2;
    mat w(N, vector&amp;lt;int&amp;gt;(N));

    for(int i=0; i&amp;lt;v.size(); i++)
        for(int j=0; j&amp;lt;u[0].size(); j++)
            for(int k=0; k&amp;lt;v[0].size(); k++)
                w[i][j] = (w[i][j] + v[i][k] * u[k][j]) % mod;

    return w;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int M; cin &amp;gt;&amp;gt; M;

    vector&amp;lt;int&amp;gt; v(2);

    for(int t=0; t&amp;lt;2; t++) {
        int N = M + t;

        mat mul(2, vector&amp;lt;int&amp;gt;(2));
        for(int i=0; i&amp;lt;2; i++) mul[i][i] = 1;

        mat ba(2, vector&amp;lt;int&amp;gt;(2));
        ba = {{1, 1}, {1, 0}};

        while(N &amp;gt; 0) {
            if(N % 2 == 1) mul = f(mul, ba);

            ba = f(ba, ba);
            N /= 2;
        }

        v[t] = mul[0][1];
    }

    int ans = (v[0] * v[1]) % mod;

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/알고리즘 공부 내용 정리</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/611</guid>
      <comments>https://restudycafe.tistory.com/611#entry611comment</comments>
      <pubDate>Thu, 18 Aug 2022 12:10:49 +0900</pubDate>
    </item>
    <item>
      <title>백준 BOJ 빠른 거듭제곱 알고리즘 (인접 행렬 활용 등) 문제 풀이 모음</title>
      <link>https://restudycafe.tistory.com/610</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 12987번 : Matrix Again&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주어진 행렬 A에 대해, S = A + A^2 + ... + A^K를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단일 행렬에 대한 거듭제곱은 N^2 log K 시간에 구할 수 있으나, 식 S의 경우에는 그러한 방식을 쓰더라도 결국 각 항을 따로 구하면 시간 복잡도가 늘어난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 이 문제에서는 점화식을 사용하여 분할 정복으로 문제를 풀어주어야 되는데, 점화식은 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1465&quot; data-origin-height=&quot;1409&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmmRRw/btrJRYdlfWK/bqtK8KYAG9mhWu9KICM25k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmmRRw/btrJRYdlfWK/bqtK8KYAG9mhWu9KICM25k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmmRRw/btrJRYdlfWK/bqtK8KYAG9mhWu9KICM25k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmmRRw%2FbtrJRYdlfWK%2FbqtK8KYAG9mhWu9KICM25k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;535&quot; height=&quot;515&quot; data-origin-width=&quot;1465&quot; data-origin-height=&quot;1409&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 점화식을 세우면 K를 계속해서 2로 나눠가면서 log 시간 복잡도로 식의 값을 구할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 ( i ) 케이스의 A^(K/2)는 분할 정복을 이용한 거듭제곱 알고리즘을 사용하여 log(K) 시간에 구해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구현해야 하는 함수가 많아서 복잡할 수 있지만, 어떤 부분을 나눠야 하는지 잘 생각하면서 하면 구현할 수 있을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 시간 초과가 발생할 수 있는데, 아래 코드의 mul 함수에서 mod 처리를 하는 과정이 요인이 될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 w[i][j] = (w[i][j] + v[i][k] * u[k][j]) % mod와 같이 식을 세울 경우, 단일 덧셈마다 mod 처리를 하여 N^3번의 나눗셈이 발생하는데, 이를 줄이기 위해 k에 대한 루프가 끝난 이후에 한 번만 나누도록 해주면 시간을 많이 단축시킬 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660704356876&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

typedef vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; mat;

int N, K, mod;

mat mul(mat v, mat u) {
    mat w(N, vector&amp;lt;int&amp;gt;(N));

    for(int i=0; i&amp;lt;N; i++)
        for(int j=0; j&amp;lt;N; j++) {
            for(int k=0; k&amp;lt;N; k++) w[i][j] += v[i][k] * u[k][j];

            w[i][j] %= mod;
        }

    return w;
}

mat fpow(mat ba, int K) {
    mat v(N, vector&amp;lt;int&amp;gt;(N));

    for(int i=0; i&amp;lt;N; i++) v[i][i] = 1;

    while(K &amp;gt; 0) {
        if(K % 2 == 1) v = mul(v, ba);

        ba = mul(ba, ba);
        K /= 2;
    }

    return v;
}

mat f(mat ba, int K) {
    if(K == 1) return ba;

    if(K % 2 == 0) {
        mat v = f(ba, K/2);
        mat u = fpow(ba, K/2);

        for(int i=0; i&amp;lt;N; i++) u[i][i] = (u[i][i] + 1) % mod;

        mat w = mul(v, u);

        return w;
    }

    if(K % 2 == 1) {
        mat v = f(ba, K-1);
        mat u = fpow(ba, K);

        for(int i=0; i&amp;lt;N; i++)
            for(int j=0; j&amp;lt;N; j++)
                v[i][j] = (v[i][j] + u[i][j]) % mod;

        return v;
    }
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; K &amp;gt;&amp;gt; mod;

    mat v(N, vector&amp;lt;int&amp;gt;(N));

    for(int i=0; i&amp;lt;N; i++)
        for(int j=0; j&amp;lt;N; j++) {
            cin &amp;gt;&amp;gt; v[i][j];

            v[i][j] = ((v[i][j] % mod) + mod) % mod;
        }

    mat ans = f(v, K);

    for(int i=0; i&amp;lt;N; i++) {
        for(int j=0; j&amp;lt;N; j++) cout &amp;lt;&amp;lt; ans[i][j] &amp;lt;&amp;lt; &quot; &quot;;

        cout &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 13246번 : 행렬 제곱의 합&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 문제와 동일한 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;풀이도 같으나, mod 부분만 변수가 아닌 고정값 1,000으로 수정해서 풀이해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중복되는 부분이 많아 풀이 코드는 아래의 접은 글에 정리해두었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1660705077465&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

typedef vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; mat;

int N, K, mod = 1e3;

mat mul(mat v, mat u) {
    mat w(N, vector&amp;lt;int&amp;gt;(N));

    for(int i=0; i&amp;lt;N; i++)
        for(int j=0; j&amp;lt;N; j++) {
            for(int k=0; k&amp;lt;N; k++) w[i][j] += v[i][k] * u[k][j];

            w[i][j] %= mod;
        }

    return w;
}

mat fpow(mat ba, int K) {
    mat v(N, vector&amp;lt;int&amp;gt;(N));

    for(int i=0; i&amp;lt;N; i++) v[i][i] = 1;

    while(K &amp;gt; 0) {
        if(K % 2 == 1) v = mul(v, ba);

        ba = mul(ba, ba);
        K /= 2;
    }

    return v;
}

mat f(mat ba, int K) {
    if(K == 1) return ba;

    if(K % 2 == 0) {
        mat v = f(ba, K/2);
        mat u = fpow(ba, K/2);

        for(int i=0; i&amp;lt;N; i++) u[i][i] = (u[i][i] + 1) % mod;

        mat w = mul(v, u);

        return w;
    }

    if(K % 2 == 1) {
        mat v = f(ba, K-1);
        mat u = fpow(ba, K);

        for(int i=0; i&amp;lt;N; i++)
            for(int j=0; j&amp;lt;N; j++)
                v[i][j] = (v[i][j] + u[i][j]) % mod;

        return v;
    }
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; K;

    mat v(N, vector&amp;lt;int&amp;gt;(N));

    for(int i=0; i&amp;lt;N; i++)
        for(int j=0; j&amp;lt;N; j++) {
            cin &amp;gt;&amp;gt; v[i][j];

            v[i][j] = ((v[i][j] % mod) + mod) % mod;
        }

    mat ans = f(v, K);

    for(int i=0; i&amp;lt;N; i++) {
        for(int j=0; j&amp;lt;N; j++) cout &amp;lt;&amp;lt; ans[i][j] &amp;lt;&amp;lt; &quot; &quot;;

        cout &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 15712번 : 등비수열&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 항이 a, 공비가 r, 항의 수가 N인 등비수열의 합을 mod로 나눈 나머지를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 mod 값이 소수였다면, 등비수열의 합 공식을 사용한 뒤 페르마의 소정리를 사용하여 아주 간단하게 풀이할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 여기서는 그러한 조건이 없으므로, 직접 항들을 계산하는 방식을 생각해보아야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1461&quot; data-origin-height=&quot;1733&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tTstq/btrJRkVmiNy/bLpjKkDI3X4lQLtYpgWdn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tTstq/btrJRkVmiNy/bLpjKkDI3X4lQLtYpgWdn0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tTstq/btrJRkVmiNy/bLpjKkDI3X4lQLtYpgWdn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtTstq%2FbtrJRkVmiNy%2FbLpjKkDI3X4lQLtYpgWdn0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;575&quot; height=&quot;682&quot; data-origin-width=&quot;1461&quot; data-origin-height=&quot;1733&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 사용한 분할 정복의 방식을 사용하면, 항의 개수의 log 값에 비례한 수행 시간으로 답을 얻을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구현 자체도 거의 비슷하고, 행렬 대신 정수에 대한 연산이므로 비교적 간단하게 풀이할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 위에서 풀이한 방식대로 하면 N = 1인 경우 무한 루프를 돌게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 N = 1인 경우 a % mod를 답으로 출력하여 예외 처리를 해주도록 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660708754930&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

int a, r, N, mod;

int fpow(int ba, int ex) {
    int val = 1;

    while(ex &amp;gt; 0) {
        if(ex % 2 == 1) val = (val * ba) % mod;

        ba = (ba * ba) % mod;
        ex /= 2;
    }

    return val;
}

int f(int ba, int ex) {
    if(ex == 1) return ba;

    if(ex % 2 == 0) {
        int a = f(ba, ex/2);
        int b = fpow(ba, ex/2);

        return (a * (b + 1)) % mod;
    }

    if(ex % 2 == 1) {
        int a = f(ba, ex-1);
        int b = fpow(ba, ex);

        return (a + b) % mod;
    }
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; r &amp;gt;&amp;gt; N &amp;gt;&amp;gt; mod;

    if(N == 1) {
        cout &amp;lt;&amp;lt; a % mod &amp;lt;&amp;lt; &quot;\n&quot;;

        return 0;
    }

    int ans = f(r % mod, N-1);

    ans = ((ans + 1) * a) % mod;

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 12850번 : 본대 산책2&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;940&quot; data-origin-height=&quot;644&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/scy5s/btrJSW8Jlo2/xqUxSKQh52Ufvfitx019v0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/scy5s/btrJSW8Jlo2/xqUxSKQh52Ufvfitx019v0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/scy5s/btrJSW8Jlo2/xqUxSKQh52Ufvfitx019v0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fscy5s%2FbtrJSW8Jlo2%2FxqUxSKQh52Ufvfitx019v0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;596&quot; height=&quot;408&quot; data-origin-width=&quot;940&quot; data-origin-height=&quot;644&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 그래프가 주어질 때, 정보과학관에서 출발하여 N번 이동 후 다시 정보과학관으로 돌아오는 경우의 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;8 x 8 크기의 인접 그래프를 만들어 준 뒤, 이를 N 제곱했을 때 얻어지는 행렬의 원소 a_ij는 i번 노드에서 인접한 노드로 N번 이동하여 j번 노드에 도달하는 경우의 수가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐하면 예를 들어 행렬을 2번 곱, 즉 제곱했다면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;a_ij는 모든 k에 대한 a_ik * a_kj이므로, i에서 k로 이동하는 경우의 수에 k에서 j로 이동하는 경우의 수의 합&lt;/span&gt;인 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 방식을 귀납적으로 생각해보면 인접 행렬을 N 제곱해주면 결국&lt;span&gt;&amp;nbsp;&lt;/span&gt;a_ij는 i번 노드에서 인접한 노드로 N번 이동하여 j번 노드에 도달하는 경우의 수가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 주어진 그래프의 번호만 편한대로 적절히 매겨서 빠른 거듭 제곱을 해준 뒤, 정보과학관에서 정보과학관으로 이동하는 것이므로 해당하는 원소를 답으로 얻어주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660733563038&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

typedef vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; mat;
int N = 8, ex, mod = 1e9 + 7;

mat f(mat&amp;amp; v, mat&amp;amp; u) {
    mat w(N, vector&amp;lt;int&amp;gt;(N));

    for(int i=0; i&amp;lt;N; i++)
        for(int j=0; j&amp;lt;N; j++)
            for(int k=0; k&amp;lt;N; k++)
                w[i][j] = (w[i][j] + v[i][k] * u[k][j]) % mod;

    return w;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    cin &amp;gt;&amp;gt; ex;

    mat v(N, vector&amp;lt;int&amp;gt;(N));
    for(int i=0; i&amp;lt;N; i++) v[i][i] = 1;

    mat ba(N, vector&amp;lt;int&amp;gt;(N));

    ba = {{0, 1, 1, 0, 0, 0, 0, 0},
          {1, 0, 1, 1, 0, 0, 0, 0},
          {1, 1, 0, 1, 1, 0, 0, 0},
          {0, 1, 1, 0, 1, 1, 0, 0},
          {0, 0, 1, 1, 0, 1, 0, 1},
          {0, 0, 0, 1, 1, 0, 1, 0},
          {0, 0, 0, 0, 0, 1, 0, 1},
          {0, 0, 0, 0, 1, 0, 1, 0}};

    while(ex &amp;gt; 0) {
        if(ex % 2 == 1) v = f(v, ba);

        ba = f(ba, ba);
        ex /= 2;
    }

    cout &amp;lt;&amp;lt; v[0][0] &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 14289번 : 본대 산책3&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;그래프 이론, 분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 문제와 동일하나, 노드의 수와 그래프의 간선들, 그리고 시간을 변수로 주는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 인접 행렬을 변수로 받아주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N x N 크기의 인접 행렬을 만들고, a번 노드와 b번 사이에 직접적인 간선이 존재한다면 v[a][b] = v[b][a] = 1로 설정해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래라면 ++ 연산을 해주어야겠지만 이 문제에서는 같은 간선이 두 개 이상 나오지 않는다고 보장해주었으므로 위와 같이 작성해도 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나머지 구현은 본대 산책2 문제와 동일하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660733563043&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

typedef vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; mat;
int N, M, ex, mod = 1e9 + 7;

mat f(mat&amp;amp; v, mat&amp;amp; u) {
    mat w(N, vector&amp;lt;int&amp;gt;(N));

    for(int i=0; i&amp;lt;N; i++)
        for(int j=0; j&amp;lt;N; j++)
            for(int k=0; k&amp;lt;N; k++)
                w[i][j] = (w[i][j] + v[i][k] * u[k][j]) % mod;

    return w;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    mat v(N, vector&amp;lt;int&amp;gt;(N));
    for(int i=0; i&amp;lt;N; i++) v[i][i] = 1;

    mat ba(N, vector&amp;lt;int&amp;gt;(N));

    while(M--) {
        int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

        ba[a-1][b-1] = ba[b-1][a-1] = 1;
    }

    cin &amp;gt;&amp;gt; ex;

    while(ex &amp;gt; 0) {
        if(ex % 2 == 1) v = f(v, ba);

        ba = f(ba, ba);
        ex /= 2;
    }

    cout &amp;lt;&amp;lt; v[0][0] &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 15824번 : 너 봄에는 캡사이신이 맛있단다&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 수 중에서 부분 수열을 골랐을 때, 그 부분 수열의 최댓값에서 최솟값을 뺀 값이 주헌고통지수라고 할 때, 가능한 모든 조합의 주헌고통지수의 합을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제에서 정의된 주헌고통지수는 오직 부분 수열의 최대/최소에만 영향이 있으므로, 수열을 정렬한 뒤 생각해도 답에는 영향이 없다. 따라서 우선 수열을 정렬하고 생각해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 &lt;span style=&quot;color: #ee2323;&quot;&gt;최솟값이 l번째이고, 최댓값이 r번째인 부분 수열을 생각해보면 [v_l , ... , v_r]인 수열의 종류는 l+1, ... , r-1번째 수를 각각 선택 또는 선택하지 않을 수 있으므로 2^(r - l - 1)가지이고 주헌고통지수의 합은 2^(r - l - 1) x (v_r - v_l)&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 r - l이 같은 값들에 대해 모든 조합들을 생각해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 r - l = 1인 조합들에 대해서 생각해보면, 이들의 합은 2^(1 - 1) x (v_2 - v_1 + v_3 - v_2 + ... + v_N - v_(N-1)) = v_N - v_1이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;r - l = 2인 조합들에 대해 생각해보면, 이들의 합은 2^(2 - 1) x (v_3 - v_1 + v_4 - v_2 + ... + v_N - v_(N-2)) = 2 x (v_N + v_(N-1) - v_2 - v_1)이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;규칙을 보면 &lt;span style=&quot;color: #ee2323;&quot;&gt;2^(r - l - 1) x (v_N + ... + v_(N - (r - l + 1)) - (v_1 + v_2 + ... + v_(r - l))&lt;/span&gt;이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이 식을 r - l 으로 나올 수 있는 값인 1 ~ N-1에 대해 모두 더해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;식을 잘 정리하면 풀이 코드를 아래와 같이 정리할 수 있는데, 이는 아래의 내 풀이를 직접 참고하는 것을 추천한다. (누적 합을 사용하면 조금 간단하게 풀이할 수 있다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 모듈로 연산을 잘못 할 경우 음수가 나오거나 하여 WA를 받을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;모듈로는 정렬이 끝나고, 각 연산에 대해 v_r - v_l을 구한 뒤부터&lt;/span&gt; 해주도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660715319026&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    int mod = 1e9 + 7;

    vector&amp;lt;int&amp;gt; v(N);
    for(int i=0; i&amp;lt;N; i++) cin &amp;gt;&amp;gt; v[i];

    sort(v.begin(), v.end());

    vector&amp;lt;int&amp;gt; u(N); u[0] = v[0];
    for(int i=1; i&amp;lt;N; i++) u[i] = u[i-1] + v[i];

    vector&amp;lt;int&amp;gt; w(N); w[N-1] = v[N-1];
    for(int i=N-2; i&amp;gt;=0; i--) w[i] = w[i+1] + v[i];

    int ans = 0;

    for(int i=0; i&amp;lt;N; i++) {
        int val = (w[N-1-i] - u[i]) % mod, ba = 2, ex = i;

        while(ex &amp;gt; 0) {
            if(ex % 2 == 1) val = (val * ba) % mod;

            ba = (ba * ba) % mod;
            ex /= 2;
        }

        ans = (ans + val) % mod;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 13075번 : Fibonacci Sequence&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;피보나치 수열의 N번째 항을 구하는 문제이다. (mod 1e9)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 행렬의 거듭제곱을 이용하여 답을 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전에 많이 다루었던 문제들이므로 설명은 생략하며, 역시 접은 글에 풀이 코드를 첨부한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1660705344286&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

typedef vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; mat;
int mod = 1e9;

mat f(mat&amp;amp; v, mat&amp;amp; u) {
    int N = 2;
    mat w(N, vector&amp;lt;int&amp;gt;(N));

    for(int i=0; i&amp;lt;v.size(); i++)
        for(int j=0; j&amp;lt;u[0].size(); j++)
            for(int k=0; k&amp;lt;v[0].size(); k++)
                w[i][j] = (w[i][j] + v[i][k] * u[k][j]) % mod;

    return w;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    while(T--) {
        int N; cin &amp;gt;&amp;gt; N;

        mat mul(2, vector&amp;lt;int&amp;gt;(2));
        for(int i=0; i&amp;lt;2; i++) mul[i][i] = 1;

        mat ba(2, vector&amp;lt;int&amp;gt;(2));
        ba = {{1, 1}, {1, 0}};

        while(N &amp;gt; 0) {
            if(N % 2 == 1) mul = f(mul, ba);

            ba = f(ba, ba);
            N /= 2;
        }

        cout &amp;lt;&amp;lt; mul[0][1] &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 2086번 : 피보나치 수의 합&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;피보나치 수열의 1항을 1, 2항을 1이라고 할 때, a, b에 대해 a번째부터 b번째 피보나치 수의 합을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 다음 코드로 피보나치 수열과 1 ~ i번째 항의 합을 두 줄에 걸쳐 나타내어보면 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드는 접은 글에 있다. (정답 코드 아님)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1660727361079&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;int&amp;gt; v(N+1);
    v[1] = 1;

    for(int i=2; i&amp;lt;=N; i++) v[i] = v[i-1] + v[i-2];

    for(int i=1; i&amp;lt;=N; i++) printf(&quot;%5d&quot;, v[i]);
    printf(&quot;\n&quot;);

    for(int i=1; i&amp;lt;=N; i++) {
        v[i] += v[i-1];

        printf(&quot;%5d&quot;, v[i]);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;805&quot; data-origin-height=&quot;366&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5cr0B/btrJWmyoCbX/qfwldjJBEfhSEZ1qeXI1fk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5cr0B/btrJWmyoCbX/qfwldjJBEfhSEZ1qeXI1fk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5cr0B/btrJWmyoCbX/qfwldjJBEfhSEZ1qeXI1fk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5cr0B%2FbtrJWmyoCbX%2FqfwldjJBEfhSEZ1qeXI1fk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;805&quot; height=&quot;366&quot; data-origin-width=&quot;805&quot; data-origin-height=&quot;366&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;규칙성을 찾아보면, 1 ~ N번째 피보나치 수열의 합은 N+2번째 피보나치 수 - 1임을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 분할 정복을 이용한 거듭제곱을 이용하여 (b+2번째 피보나치 수 - 1) - (a+2-1번째 피보나치 수 - 1) = (b+2번째 피보나치 수 ) - (a+1번째 피보나치 수)를 답으로 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 모듈로에 의해 뒤의 수가 더 클 수도 있으므로, 모듈로를 한 번 더한 뒤 모듈로 처리를 해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660727656841&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

typedef vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; mat;
int mod = 1e9;

mat f(mat&amp;amp; v, mat&amp;amp; u) {
    int N = 2;
    mat w(N, vector&amp;lt;int&amp;gt;(N));

    for(int i=0; i&amp;lt;v.size(); i++)
        for(int j=0; j&amp;lt;u[0].size(); j++)
            for(int k=0; k&amp;lt;v[0].size(); k++)
                w[i][j] = (w[i][j] + v[i][k] * u[k][j]) % mod;

    return w;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    vector&amp;lt;int&amp;gt; v(2);
    for(int i=0; i&amp;lt;2; i++) cin &amp;gt;&amp;gt; v[i];

    v[0] += 2 - 1;
    v[1] += 2;

    vector&amp;lt;int&amp;gt; u(2);

    for(int t=0; t&amp;lt;2; t++) {
        int N = v[t];

        mat mul(2, vector&amp;lt;int&amp;gt;(2));
        for(int i=0; i&amp;lt;2; i++) mul[i][i] = 1;

        mat ba(2, vector&amp;lt;int&amp;gt;(2));
        ba = {{1, 1}, {1, 0}};

        while(N &amp;gt; 0) {
            if(N % 2 == 1) mul = f(mul, ba);

            ba = f(ba, ba);
            N /= 2;
        }

        u[t] = mul[0][1];
    }

    int ans = (u[1] - u[0] + mod) % mod;

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 11238번 : Fibo&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;정수론, 분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;10억 이하의 a 또는 b에 대해 a번째 피보나치 수와 b번째 피보나치 수의 최대공약수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 분할 정복을 이용한 거듭제곱으로 a 또는 b번째 피보나치 수를 구할 수는 있으나, 모듈로 연산을 해버리면 gcd 값이 달라지므로 다른 방법을 생각해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;피보나치 수의 성질 중 하나로 a번째 피보나치 수와 b번째 피보나치 수의 최대공약수는 (a와 b의 최대공약수)번째 피보나치수임을 만족한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;증명 과정을 읽어봤는데 a와 b에 대해 유클리드 호제법을 사용함과 동시에 몇 가지 Lemma들을 사용하여 증명한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 성질은 분명 중요하지만, 이런 증명 과정 자체가 PS에서 자주 사용되지는 않는다고 생각하기에 여기서는 증명 과정 없이 이러한 성질을 활용하여 풀이한 코드만 첨부한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660732054889&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

typedef vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; mat;
int mod = 1e9 + 7;

mat f(mat&amp;amp; v, mat&amp;amp; u) {
    int N = 2;
    mat w(N, vector&amp;lt;int&amp;gt;(N));

    for(int i=0; i&amp;lt;v.size(); i++)
        for(int j=0; j&amp;lt;u[0].size(); j++)
            for(int k=0; k&amp;lt;v[0].size(); k++)
                w[i][j] = (w[i][j] + v[i][k] * u[k][j]) % mod;

    return w;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    while(T--) {
        int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

        int N = __gcd(a, b);

        mat mul(2, vector&amp;lt;int&amp;gt;(2));
        for(int i=0; i&amp;lt;2; i++) mul[i][i] = 1;

        mat ba(2, vector&amp;lt;int&amp;gt;(2));
        ba = {{1, 1}, {1, 0}};

        while(N &amp;gt; 0) {
            if(N % 2 == 1) mul = f(mul, ba);

            ba = f(ba, ba);
            N /= 2;
        }

        cout &amp;lt;&amp;lt; mul[0][1] &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 11778번 : 피보나치 수와 최대공약수&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;정수론, 분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 문제와 동일한 문제이다. (문제 언어만 다르다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 방식으로 풀이해주되, 테스트케이스 처리부만 제거해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중복 문제이므로 접은 글에 풀이 코드를 첨부한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1660732523354&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

typedef vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; mat;
int mod = 1e9 + 7;

mat f(mat&amp;amp; v, mat&amp;amp; u) {
    int N = 2;
    mat w(N, vector&amp;lt;int&amp;gt;(N));

    for(int i=0; i&amp;lt;v.size(); i++)
        for(int j=0; j&amp;lt;u[0].size(); j++)
            for(int k=0; k&amp;lt;v[0].size(); k++)
                w[i][j] = (w[i][j] + v[i][k] * u[k][j]) % mod;

    return w;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

    int N = __gcd(a, b);

    mat mul(2, vector&amp;lt;int&amp;gt;(2));
    for(int i=0; i&amp;lt;2; i++) mul[i][i] = 1;

    mat ba(2, vector&amp;lt;int&amp;gt;(2));
    ba = {{1, 1}, {1, 0}};

    while(N &amp;gt; 0) {
        if(N % 2 == 1) mul = f(mul, ba);

        ba = f(ba, ba);
        N /= 2;
    }

    cout &amp;lt;&amp;lt; mul[0][1] &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 16134번 : 조합 (Combination)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N C M mod 1e9 + 7을 구하는 문제이다. 이 때 0 &amp;le; M &amp;le; N &amp;le; 1,000,000이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 페르마의 소정리를 활용하여 mod 값을 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N! mod 1e9 + 7은 O(N)에 구할 수 있고, 분모의 경우에는 하나의 분모당 log(1e9 + 7) 시간에 수행할 수 있으므로, O(M log mod) 시간에 풀이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660747100824&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    M = min(M, N - M);

    int ans = 1, mod = 1e9 + 7;

    for(int i=N; i&amp;gt;=N-M+1; i--) ans = (ans * i) % mod;

    for(int i=1; i&amp;lt;=M; i++) {
        int ba = i, ex = mod - 2;

        while(ex &amp;gt; 0) {
            if(ex % 2 == 1) ans = (ans * ba) % mod;

            ba = (ba * ba) % mod;
            ex /= 2;
        }
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/알고리즘 공부 내용 정리</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/610</guid>
      <comments>https://restudycafe.tistory.com/610#entry610comment</comments>
      <pubDate>Wed, 17 Aug 2022 12:04:07 +0900</pubDate>
    </item>
    <item>
      <title>백준 BOJ 분할 정복을 이용한 거듭제곱 문제 풀이 모음 220816</title>
      <link>https://restudycafe.tistory.com/609</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 12878번 : Blocks&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 블럭을 각각 빨강, 주황, 노랑, 초록색 중 하나로 칠하는데 그들 중 빨간색으로 칠해진 블럭과 노란색으로 칠해진 블럭이 각각 짝수개인 경우의 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 간단한 해결책은 N = 5 정도까지 완전 탐색으로 모든 경우를 count 해본 뒤, 규칙을 찾아 일반항을 찾는 방법이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;2000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcjqYj/btrJRXELVFD/eQkleVXoEOFyQpvMHfdCz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcjqYj/btrJRXELVFD/eQkleVXoEOFyQpvMHfdCz1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcjqYj/btrJRXELVFD/eQkleVXoEOFyQpvMHfdCz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcjqYj%2FbtrJRXELVFD%2FeQkleVXoEOFyQpvMHfdCz1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;615&quot; height=&quot;769&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;2000&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직접 계산하는 방법은 위와 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빨간색 또는 노란색으로 칠할 블럭을 선택하고, 그들 중 빨간색으로 칠할 블럭을 고른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나머지 블럭 중에서는 초록색 또는 주황색 중 어떤 색으로 칠할지를 고른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제의 식 유도에서 핵심은 NC0 + NC2 + NC4 + ... = 2^(N-1)임을 알고 있어야 한다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;홀수인 경우에도 똑같이 2^(N-1)이니 까먹지 않도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N이 최대 10^9이므로 O(N) 시간도 부족하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 분할 정복을 이용한 거듭제곱을 이용하여 log 시간에 거듭제곱을 수행할 수 있도록 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660640450529&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    int mod = 1e4 + 7;

    int a = 1, ba = 2, ex = N-1;

    while(ex &amp;gt; 0) {
        if(ex % 2 == 1) a = (a * ba) % mod;

        ba = (ba * ba) % mod;
        ex /= 2;
    }

    int b = 1; ba = 2, ex = 2*(N-1);

    while(ex &amp;gt; 0) {
        if(ex % 2 == 1) b = (b * ba) % mod;

        ba = (ba * ba) % mod;
        ex /= 2;
    }

    int ans = (a + b) % mod;

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 11693번 : n^m의 약수의 합&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;n^m의 모든 약수의 합 mod (1e9 + 7)의 값을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1273&quot; data-origin-height=&quot;689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZ0haZ/btrJRsS4ggd/Lo5C9VOjNSRw6XZ5PFAVxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZ0haZ/btrJRsS4ggd/Lo5C9VOjNSRw6XZ5PFAVxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZ0haZ/btrJRsS4ggd/Lo5C9VOjNSRw6XZ5PFAVxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZ0haZ%2FbtrJRsS4ggd%2FLo5C9VOjNSRw6XZ5PFAVxk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;527&quot; height=&quot;285&quot; data-origin-width=&quot;1273&quot; data-origin-height=&quot;689&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단히 식 개형만 정리해보면 위와 같이 약수의 합을 (1 + p + p^2 + ... + p^kM) x (1 + q + q^2 + ... ) x ... 이런 식으로 나타낼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 p^k는 N을 소인수분해 했을 때 나타나는 p의 최고 지수이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제에서는 N을 M 제곱했기 때문에 최고 차항은 kM이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 항들을 일일이 더하면 결국 O(kM) 이상의 시간이 걸리므로 시간 초과가 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 이를 빨리 구해주기 위해 위에서 정리한 등비수열의 합 공식을 사용해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분모의 경우에는 모듈로 역원 공식을 사용해서 풀어주면 된다. (a^(-1) &amp;equiv; a^(p - 2) (mod p))&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660655578223&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    vector&amp;lt;int&amp;gt; v;

    int tmp = N;

    for(int i=2; i*i&amp;lt;=tmp; i++) {
        while(tmp % i == 0) {
            v.push_back(i);
            tmp /= i;
        }
    }

    if(tmp &amp;gt; 1) v.push_back(tmp);

    int cnt = 1, ans = 1, mod = 1e9 + 7;

    for(int i=1; i&amp;lt;v.size(); i++) {
        if(v[i] == v[i-1]) cnt++;
        else {
            int mul = 1, ba = v[i-1], ex = cnt*M + 1;

            while(ex &amp;gt; 0) {
                if(ex % 2 == 1) mul = (mul * ba) % mod;

                ba = (ba * ba) % mod;
                ex /= 2;
            }

            mul--;

            ba = v[i-1] - 1, ex = mod - 2;

            while(ex &amp;gt; 0) {
                if(ex % 2 == 1) mul = (mul * ba) % mod;

                ba = (ba * ba) % mod;
                ex /= 2;
            }

            ans = (ans * mul) % mod;

            cnt = 1;
        }
    }

    if(v.size() &amp;gt; 0) {
        int mul = 1, ba = v[v.size()-1], ex = cnt*M + 1;

        while(ex &amp;gt; 0) {
            if(ex % 2 == 1) mul = (mul * ba) % mod;

            ba = (ba * ba) % mod;
            ex /= 2;
        }

        mul--;

        ba = v[v.size()-1] - 1, ex = mod - 2;

        while(ex &amp;gt; 0) {
            if(ex % 2 == 1) mul = (mul * ba) % mod;

            ba = (ba * ba) % mod;
            ex /= 2;
        }

        ans = (ans * mul) % mod;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 7677번 : Fibonacci&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;피보나치 수에 대한 일반화 된 행렬 식을 주고, F_n을 구하게 하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제에서 행렬과 일반항에 대한 식을 모두 주었기 때문에 단순히 행렬을 N 제곱하여 F_N에 해당하는 원소의 값을 출력해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660645696414&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

typedef vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; mat;
int mod = 1e4;

mat f(mat&amp;amp; v, mat&amp;amp; u) {
    int N = 2;
    mat w(N, vector&amp;lt;int&amp;gt;(N));

    for(int i=0; i&amp;lt;v.size(); i++)
        for(int j=0; j&amp;lt;u[0].size(); j++)
            for(int k=0; k&amp;lt;v[0].size(); k++)
                w[i][j] = (w[i][j] + v[i][k] * u[k][j]) % mod;

    return w;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    while(true) {
        int N; cin &amp;gt;&amp;gt; N;
        if(N == -1) break;

        mat mul(2, vector&amp;lt;int&amp;gt;(2));
        for(int i=0; i&amp;lt;2; i++) mul[i][i] = 1;

        mat ba(2, vector&amp;lt;int&amp;gt;(2));
        ba = {{1, 1}, {1, 0}};

        while(N &amp;gt; 0) {
            if(N % 2 == 1) mul = f(mul, ba);

            ba = f(ba, ba);
            N /= 2;
        }

        cout &amp;lt;&amp;lt; mul[0][1] &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 11442번 : 홀수번째 피보나치 수의 합&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 이름 그대로 홀수번째 피보나치 수의 합을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 F_0 = 0, F_1 = 1이며, 합을 1e9 + 7로 나눈 수를 답으로 제출해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;616&quot; data-origin-height=&quot;531&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cq2L3N/btrJREMl6Hx/adoclZGNuWTPkgd7n0CWCK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cq2L3N/btrJREMl6Hx/adoclZGNuWTPkgd7n0CWCK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cq2L3N/btrJREMl6Hx/adoclZGNuWTPkgd7n0CWCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcq2L3N%2FbtrJREMl6Hx%2FadoclZGNuWTPkgd7n0CWCK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;522&quot; height=&quot;450&quot; data-origin-width=&quot;616&quot; data-origin-height=&quot;531&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엄밀하게는 점화식이나 일반항을 찾아도 좋지만, 굳이 엄밀하게 풀 것이 아니라면 규칙성을 찾아서 풀어도 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5줄까지만 적어보면 위와 같이 f(2k + 1) = f(2k) = F_2k임을 알 수 있다. (F_2k는 2k번째 피보나치 수)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 2k번째 피보나치 수만 행렬과 빠른 거듭제곱을 활용하여 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660646610008&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

typedef vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; mat;
int mod = 1e9 + 7;

mat f(mat&amp;amp; v, mat&amp;amp; u) {
    int N = 2;
    mat w(N, vector&amp;lt;int&amp;gt;(N));

    for(int i=0; i&amp;lt;v.size(); i++)
        for(int j=0; j&amp;lt;u[0].size(); j++)
            for(int k=0; k&amp;lt;v[0].size(); k++)
                w[i][j] = (w[i][j] + v[i][k] * u[k][j]) % mod;

    return w;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    if(N % 2 == 1) N++;

    mat mul(2, vector&amp;lt;int&amp;gt;(2));
    for(int i=0; i&amp;lt;2; i++) mul[i][i] = 1;

    mat ba(2, vector&amp;lt;int&amp;gt;(2));
    ba = {{1, 1}, {1, 0}};

    while(N &amp;gt; 0) {
        if(N % 2 == 1) mul = f(mul, ba);

        ba = f(ba, ba);
        N /= 2;
    }

    cout &amp;lt;&amp;lt; mul[0][1] &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 11443번 : 짝수번째 피보나치 수의 합&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제 역시 위의 문제와 세트 문제로, 짝수번째 피보나치 수의 합을 구해 그것을 1e9 + 7로 나눈 나머지를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;685&quot; data-origin-height=&quot;536&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/r6ybH/btrJKZYmOe1/CxKgtip4M5XSx5MKc5yNn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/r6ybH/btrJKZYmOe1/CxKgtip4M5XSx5MKc5yNn0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/r6ybH/btrJKZYmOe1/CxKgtip4M5XSx5MKc5yNn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fr6ybH%2FbtrJKZYmOe1%2FCxKgtip4M5XSx5MKc5yNn0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;555&quot; height=&quot;434&quot; data-origin-width=&quot;685&quot; data-origin-height=&quot;536&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 앞의 몇 항을 적어보면, N이 짝수일 때는 1 더해준 뒤 F_N - 1을 답으로 얻어주면 됨을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;피보나치 수의 일반항을 구하는 과정은 위의 문제와 동일하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660647842710&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

typedef vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; mat;
int mod = 1e9 + 7;

mat f(mat&amp;amp; v, mat&amp;amp; u) {
    int N = 2;
    mat w(N, vector&amp;lt;int&amp;gt;(N));

    for(int i=0; i&amp;lt;v.size(); i++)
        for(int j=0; j&amp;lt;u[0].size(); j++)
            for(int k=0; k&amp;lt;v[0].size(); k++)
                w[i][j] = (w[i][j] + v[i][k] * u[k][j]) % mod;

    return w;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    if(N % 2 == 0) N++;

    mat mul(2, vector&amp;lt;int&amp;gt;(2));
    for(int i=0; i&amp;lt;2; i++) mul[i][i] = 1;

    mat ba(2, vector&amp;lt;int&amp;gt;(2));
    ba = {{1, 1}, {1, 0}};

    while(N &amp;gt; 0) {
        if(N % 2 == 1) mul = f(mul, ba);

        ba = f(ba, ba);
        N /= 2;
    }

    cout &amp;lt;&amp;lt; mul[0][1] - 1 &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 15999번 : 뒤집기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;B 또는 W로 이루어진 N x M의 배열에서 일부 칸을 뒤집어 인접한 같은 칸들이 모두 뒤집힌다고 할 때, 원래 배열로 가능했을 것의 경우의 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뒤집고 나서 옆에 다른 칸이 존재하는 것은 불가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 상하좌우에 다른 칸이 존재하지 않는 칸은 선택했을 수도, 선택되지 않을 수도 있으므로 2^(상하좌우에 다른 칸이 존재하지 않는 칸)이 답이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660641146178&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    vector&amp;lt;vector&amp;lt;char&amp;gt;&amp;gt; v(N, vector&amp;lt;char&amp;gt;(M));

    for(int i=0; i&amp;lt;N; i++)
        for(int j=0; j&amp;lt;M; j++) cin &amp;gt;&amp;gt; v[i][j];

    int cnt = 0;

    for(int i=0; i&amp;lt;N; i++)
        for(int j=0; j&amp;lt;M; j++) {
            bool check = true;

            int di[4] = {1, -1, 0, 0};
            int dj[4] = {0, 0, 1, -1};

            for(int k=0; k&amp;lt;4; k++) {
                int ni = i + di[k];
                int nj = j + dj[k];

                if(ni &amp;lt; 0 || nj &amp;lt; 0 || ni &amp;gt;= N || nj &amp;gt;= M) continue;

                if(v[ni][nj] != v[i][j]) check = false;
            }

            if(check) cnt++;
        }

    int ans = 1, ba = 2, ex = cnt, mod = 1e9 + 7;

    while(ex &amp;gt; 0) {
        if(ex % 2 == 1) ans = (ans * ba) % mod;

        ba = (ba * ba) % mod;
        ex /= 2;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 13172번 : &amp;Sigma;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;페르마의 소정리, 분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N쌍의 주어진 a/b들에 대해서, a x b^(-1) mod (1e9 + 7)들의 합을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;페르마의 소정리를 활용하여 기약 분수를 모듈로에 대해 연산하는 방법을 알려주는 가장 기초적인 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제에서 하라는대로 구현해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;페르마의 소정리에 의하면 소수 p에 대해 a^(-1) mod p는 a^(p-2) mod p와 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, a/b mod p는 a x b^(p-2) mod p를 구하라는 것과 같고, b^(p-2)는 빠른 거듭제곱을 구현하여 풀이해줄 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660631495441&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    int ans = 0, mod = 1e9 + 7;

    while(N--) {
        int a, b; cin &amp;gt;&amp;gt; b &amp;gt;&amp;gt; a;

        int mul = a, ba = b, ex = mod - 2;

        while(ex &amp;gt; 0) {
            if(ex % 2 == 1) mul = (mul * ba) % mod;

            ba = (ba * ba) % mod;
            ex /= 2;
        }

        ans = (ans + mul) % mod;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 14440번 : 정수 수열&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수열의 a0와 a1이 주어지고, a_i = x a_(i-1) + y a_(i-2)일 때 a_N을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1145&quot; data-origin-height=&quot;741&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbZ6Qz/btrJO0JehPH/mjcriUmbVNT1wfxK6p6Ak1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbZ6Qz/btrJO0JehPH/mjcriUmbVNT1wfxK6p6Ak1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbZ6Qz/btrJO0JehPH/mjcriUmbVNT1wfxK6p6Ak1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcbZ6Qz%2FbtrJO0JehPH%2FmjcriUmbVNT1wfxK6p6Ak1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;615&quot; height=&quot;398&quot; data-origin-width=&quot;1145&quot; data-origin-height=&quot;741&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;행렬을 위와 같이 잡아 행렬 [ [x y] [1 0] ]을 (N-1)제곱하여 일반항을 구해줄 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주의할 점은 A_N의 뒤의 &quot;두 자리&quot;를 구하라고 하였으므로, 답이 한 자리거나 0인 경우 앞에 0 하나를 더 붙여서 출력해주어야 한다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660633049459&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

typedef vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; mat;
int mod = 100;

mat f(mat&amp;amp; v, mat&amp;amp; u) {
    mat w(2, vector&amp;lt;int&amp;gt;(2));

    for(int i=0; i&amp;lt;v.size(); i++)
        for(int j=0; j&amp;lt;u[0].size(); j++)
            for(int k=0; k&amp;lt;v[0].size(); k++)
                w[i][j] = (w[i][j] + v[i][k] * u[k][j]) % mod;

    return w;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int x, y, a0, a1, N; cin &amp;gt;&amp;gt; x &amp;gt;&amp;gt; y &amp;gt;&amp;gt; a0 &amp;gt;&amp;gt; a1 &amp;gt;&amp;gt; N;

    if(N == 0) {
        printf(&quot;%02d\n&quot;, x);
        return 0;
    }
    else if(N == 1) {
        printf(&quot;%02d\n&quot;, y);
        return 0;
    }

    mat mul(2, vector&amp;lt;int&amp;gt;(2));
    for(int i=0; i&amp;lt;2; i++) mul[i][i] = 1;

    mat ba(2, vector&amp;lt;int&amp;gt;(2));
    ba[0][0] = x, ba[0][1] = y, ba[1][0] = 1, ba[1][1] = 0;

    N--;

    while(N &amp;gt; 0) {
        if(N % 2 == 1) mul = f(mul, ba);

        ba = f(ba, ba);
        N /= 2;
    }

    int ans = (mul[0][0] * a1 + mul[0][1] * a0) % mod;

    printf(&quot;%02d\n&quot;, ans);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 4233번 : 가짜소수&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;에라토스테네스의 체, 분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 수 p가 소수가 아니면서 a^p &amp;equiv; a (mod p)라면 p를 가짜소수라고 할 때, a와 p가 주어졌을 때 p가 가짜소수인지를 판별하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 적어보자면 p가 가짜소수이려면, 1. 소수가 아니어야 하고 2. a^p &amp;equiv; a (mod p)이어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1번 조건은 에라토스테네스의 체를 이용하여 sqrt(p) 까지의 소수에 대해서만 나누어지는지 확인해보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2번은 분할 정복을 이용한 거듭제곱을 수행하여 O(log p) 시간에 제곱값을 구하고, 이것이 mod p에 대해 a인지 확인해보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주의할 점은 가짜소수는 합성수라는 것이다. 조건을 잘 읽어보아야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660628335572&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int Max = 1e5;

    vector&amp;lt;bool&amp;gt; p(Max, true);
    p[1] = false;

    for(int i=2; i*i&amp;lt;Max; i++)
        for(int j=2; i*j&amp;lt;Max; j++) p[i*j] = false;

    vector&amp;lt;int&amp;gt; v;
    for(int i=2; i&amp;lt;Max; i++)
        if(p[i]) v.push_back(i);

    while(true) {
        int N, a; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; a;
        if(N == 0 &amp;amp;&amp;amp; a == 0) break;

        bool check = true;

        for(int i=0; i&amp;lt;v.size() &amp;amp;&amp;amp; v[i]*v[i] &amp;lt;= N; i++) {
            if(N % v[i] == 0) check = false;
        }

        if(check) {
            cout &amp;lt;&amp;lt; &quot;no\n&quot;;
            continue;
        }

        int mul = 1, bas = a, exp = N;

        while(exp &amp;gt; 0) {
            if(exp % 2 == 1) mul = (mul * bas) % N;

            bas = (bas * bas) % N;
            exp /= 2;
        }

        if(mul == a) cout &amp;lt;&amp;lt; &quot;yes\n&quot;;
        else cout &amp;lt;&amp;lt; &quot;no\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 5095번 : Matrix Powers&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N x N 행렬을 M 제곱한 행렬을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 분할 정복을 이용한 거듭제곱 알고리즘을 이용하여 그대로 풀이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 행렬의 곱을 구현하는 부분에서 헷갈릴 수 있는데, A 행렬과 B 행렬의 곱의 경우 A 행렬의 행의 수만큼 행이 생기고, B행렬의 열의 수만큼 열이 생기며, 각 원소는 A 행렬의 열의 수 = B 행렬의 행의 수만큼의 원소들을 곱해서 더해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660630479955&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

typedef vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; mat;
int N, mod, M;

mat f(mat&amp;amp; v, mat&amp;amp; u) {
    mat w(N, vector&amp;lt;int&amp;gt;(N));

    for(int i=0; i&amp;lt;v.size(); i++)
        for(int j=0; j&amp;lt;u[0].size(); j++)
            for(int k=0; k&amp;lt;v[0].size(); k++)
                w[i][j] = (w[i][j] + v[i][k] * u[k][j]) % mod;

    return w;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    while(true) {
        cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; mod &amp;gt;&amp;gt; M;
        if(N == 0 &amp;amp;&amp;amp; mod == 0 &amp;amp;&amp;amp; M == 0) break;

        mat mul(N, vector&amp;lt;int&amp;gt;(N));
        for(int i=0; i&amp;lt;N; i++) mul[i][i] = 1;

        mat bas(N, vector&amp;lt;int&amp;gt;(N));

        for(int i=0; i&amp;lt;N; i++)
            for(int j=0; j&amp;lt;N; j++) cin &amp;gt;&amp;gt; bas[i][j];

        while(M &amp;gt; 0) {
            if(M % 2 == 1) mul = f(mul, bas);

            bas = f(bas, bas);
            M /= 2;
        }

        for(int i=0; i&amp;lt;mul.size(); i++) {
            for(int j=0; j&amp;lt;mul[0].size(); j++) cout &amp;lt;&amp;lt; mul[i][j] &amp;lt;&amp;lt; &quot; &quot;;

            cout &amp;lt;&amp;lt; &quot;\n&quot;;
        }
        cout &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 15710번 : xor 게임&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;a에서 시작하여 0 ~ 2^31 - 1의 수를 하나 골라 xor하는 과정을 N번 거쳐 b를 만드는 경우의 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중간에 나올 수 있는 수는 0 ~ 2^31 - 1 중 어떤 것이든 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 중간에 거치는 수 하나 당 2^31가지의 경우의 수가 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연산을 N번 거쳐 b가 되었다는 것은 중간 수가 N-1가지라는 의미이므로, 답은 (2^31)^(N-1)이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660625306276&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int a, b, N; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b &amp;gt;&amp;gt; N;

    int ans = 1, mod = 1e9 + 7;

    int x = 1;

    for(int i=1; i&amp;lt;=31; i++) x = (x * 2) % mod;

    N--;

    while(N &amp;gt; 0) {
        if(N % 2 == 1) ans = (ans * x) % mod;

        x = (x * x) % mod;
        N /= 2;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 15717번 : 떡파이어&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;분할 제곱을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자연수 N을 자연수들로 분할하는 경우의 수를 묻는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 N = 4인 경우 3 = 2 + 1 = 1 + 2 = 1 + 1 + 1로 4가지이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 공이 있고 그 사이에 막대로 분리하는 경우를 생각해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N-1개의 사이 공간에 막대를 각각 놓을지 안 놓을지 2가지의 선택지가 있으므로 답은 2^(N-1)이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660625786473&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    N--;

    int ans = 1, x = 2, mod = 1e9 + 7;

    while(N &amp;gt; 0) {
        if(N % 2 == 1) ans = (ans * x) % mod;

        x = (x * x) % mod;
        N /= 2;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 18291번 : 비요뜨의 징검다리 건너기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1번 다리에서 N번 다리로 건너는데, 1번과 N번 사이에 있는 다리는 건너도 되고 안 건너도 될 때, 다리를 건너는 방법의 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;선택이 가능한 다리는 N-2개이고 각각 건널지 말지를 선택할 수 있으므로, 답은 2^(N-2)이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660626199227&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    while(T--) {
        int N; cin &amp;gt;&amp;gt; N;

        if(N &amp;lt; 2) {
            cout &amp;lt;&amp;lt; 1 &amp;lt;&amp;lt; &quot;\n&quot;;
            continue;
        }

        N -= 2;

        int ans = 1, x = 2, mod = 1e9 + 7;

        while(N &amp;gt; 0) {
            if(N % 2 == 1) ans = (ans * x) % mod;

            x = (x * x) % mod;
            N /= 2;
        }

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 24930번 : Ordinary Ordinals&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N 이하의 원소를 규칙에 따라 집합으로 표현했을 때, 문자열의 길이를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수열의 규칙성 문제의 경우 점화식만 찾아주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N+1일 때, N까지의 원소들을 모두 한 번 출력하되 기존의 괄호(2개의 문자열)가 사라진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 콤마가 하나 붙고, N+1에 해당하는 원소가 같은 길이로 나오는데 이번에는 괄호가 붙어있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 전체를 감싸는 괄호가 2개 나와야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 f(N+1) = 2 x f(N) + 1임을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;f(0)에서 f(1)로 갈 때는 쉼표가 없으므로 예외 처리를 해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 점화식에서 일반항의 규칙을 잘 찾아보면 f(N) = 2^(N-2) x 10 - 1임을 알 수 있고, 2^(N-2)는 로그 시간 제곱으로 구해줄 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660624525537&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, mod; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; mod;

    if(N == 0) {
        cout &amp;lt;&amp;lt; 2 % mod &amp;lt;&amp;lt; &quot;\n&quot;;
        return 0;
    }
    else if(N == 1) {
        cout &amp;lt;&amp;lt; 4 % mod &amp;lt;&amp;lt; &quot;\n&quot;;
        return 0;
    }

    int ans = 1, a = 2;

    N -= 2;

    while(N &amp;gt; 0) {
        if(N % 2 == 1) ans = (ans * a) % mod;

        a = (a * a) % mod;
        N /= 2;
    }

    ans = (ans * 10 - 1) % mod;

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 24159번 : フェルマー方程式&amp;nbsp;(Fermat)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N과 M이 주어질 때, 0 ~ M-1 사이의 x, y, z에 대해 x^N + y^N &amp;equiv; z^N (mod M)인 (x, y, z)의 개수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;0 ~ M-1인 a에 대해 a^N의 값들을 모두 구해놓고, mod M 값이 i인 것들을 u[i]에 저장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 u[i]는 z^N, 즉 우변에 해당하는 값들이 될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 좌변의 mod 값들에 따른 개수들을 계산하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이중 for문을 이용하여 v[i] + v[j] 값들을 고려해주되, 그냥 계산하면 시간 초과가 나기 때문에 반으로 나눠서 i &amp;lt; j인 경우에 대해서만 count 해주고 나머지는 2배해주면 된다. (물론 i = j인 경우는 따로 count 해주어야 한다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 좌변과 우변이 같은 경우의 수들을 모두 세어주면 되는데, 이것은 O(M) 시간에 수행 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660622365827&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int M, N; cin &amp;gt;&amp;gt; M &amp;gt;&amp;gt; N;

    vector&amp;lt;int&amp;gt; v(M, 1), u(M);

    for(int i=0; i&amp;lt;M; i++) {
        int a = i, b = N;

        while(b &amp;gt; 0) {
            if(b % 2 == 1) v[i] = (v[i] * a) % M;

            a = (a * a) % M;
            b /= 2;
        }

        u[v[i]]++;
    }

    vector&amp;lt;int&amp;gt; w(M);

    for(int i=0; i&amp;lt;M; i++)
        for(int j=i+1; j&amp;lt;M; j++) w[(v[i] + v[j]) % M] += 2;

    for(int i=0; i&amp;lt;M; i++) w[(v[i] + v[i]) % M]++;

    int ans = 0;

    for(int i=0; i&amp;lt;M; i++) ans += u[i] * w[i];

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 14731번 : 謎紛芥索紀 (Large)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다항식이 주어질 때 f'(2)의 값을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;k x^b를 미분하면 kb x^(b-1)이 되므로, 나머지는 계산해주고 x^(b-1)을 분할 정복을 이용한 거듭제곱으로 log 시간에 계산해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 x = 2이므로, 2를 거듭제곱 해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의문인 점은 mul = k * b를 했을 때 모듈로 처리를 안하면 틀린다는 것인데, 어차피 ans = (ans + mul) % mod에서 모듈로 연산이 될텐데 어디에서 오버플로우가 났는지 잘 모르겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660619174611&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    int ans = 0, mod = 1e9 + 7;

    while(N--) {
        int k, a = 2, b; cin &amp;gt;&amp;gt; k &amp;gt;&amp;gt; b;

        int mul = (k * b) % mod;
        b--;

        while(b &amp;gt; 0) {
            if(b % 2 == 1) mul = (mul * a) % mod;

            a = (a * a) % mod;
            b /= 2;
        }

        ans = (ans + mul) % mod;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 21854번 : Monsters&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 수에 대해, 2^(a_i)의 합을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 수에 대해 2의 거듭 제곱의 값을 분할 정복을 이용한 거듭제곱으로 log 시간에 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;총 시간 복잡도는 O(N log K)가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660617997713&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    int ans = 0, mod = 1e9 + 7;

    while(N--) {
        int b; cin &amp;gt;&amp;gt; b;

        int mul = 1, a = 2;

        while(b &amp;gt; 0) {
            if(b % 2 == 1) mul = (mul * a) % mod;

            a = (a * a) % mod;
            b /= 2;
        }

        ans = (ans + mul) % mod;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 11366번 : Tons of Orcs, no Fibbin'&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;수학&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;등차수열의 첫 두 항 a와 b가 주어질 때, c+2번째 항의 값을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수가 기하급수적으로 늘어나므로 굳이 DP를 사용할 필요도 없이 단순 반복으로 계산이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 a = 0, b = 0일 경우 N을 아주 크게 주어도 답이 0으로 나오므로, 시간 초과가 발생할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 이 경우는 예외 처리를 해주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660613855359&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    while(true) {
        int a, b, N; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b &amp;gt;&amp;gt; N;
        if(a == 0 &amp;amp;&amp;amp; b == 0 &amp;amp;&amp;amp; N == 0) break;

        if(a == 0 &amp;amp;&amp;amp; b == 0) {
            cout &amp;lt;&amp;lt; 0 &amp;lt;&amp;lt; &quot;\n&quot;;
            continue;
        }

        int ans = a + b;
        N--;

        while(N--) {
            a = b;
            b = ans;
            ans = a + b;
        }

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 13171번 : A&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Silver IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;a^b의 값을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분할 정복을 사용한 거듭제곱으로 풀이해줄 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 a는 처음부터 mod 값인 1e9 + 7을 넘어가서 주어질 수 있으므로, a는 거듭제곱 전에 mod 처리를 한 번 해주고 시작해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660613754075&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

    int ans = 1, mod = 1e9 + 7;

    a %= mod;

    while(b &amp;gt; 0) {
        if(b % 2 == 1) ans = (ans * a) % mod;

        a = (a * a) % mod;
        b /= 2;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 11288번 : Ethel's Encryption&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;Bronze I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 암호문이 알파벳을 a^b만큼 shift하여 만들어졌다고 할 때, 원문을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알파벳은 총 26개이므로, a^b % 26만큼 shift 해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;a^b는 분할 정복을 이용한 거듭제곱으로 구해줄 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거듭제곱 연산마다 mod 26 처리를 해주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660613464443&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, a, b; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;
    cin.ignore();

    string str; getline(cin, str);

    int mul = 1;

    while(b &amp;gt; 0) {
        if(b % 2 == 1) mul = (mul * a) % 26;

        a = (a * a) % 26;
        b /= 2;
    }

    for(int i=0; i&amp;lt;str.length(); i++) {
        if(str[i] == ' ') {
            cout &amp;lt;&amp;lt; &quot; &quot;;
            continue;
        }

        str[i] = char('A' + (str[i] - 'A' - mul + 26) % 26);

        cout &amp;lt;&amp;lt; str[i];
    }
    cout &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 11524번 : Immortal Propoises&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;분할 정복을 이용한 거듭제곱&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1,000개 이하의 테스트케이스에 대해 N번째 피보나치 수를 구하는 문제이다. (이 때 N &amp;le; 2^48)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 풀이를 위에서 여러 번 다루었으므로 설명은 생략한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660654253864&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

typedef vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; mat;
int mod = 1e9;

mat f(mat&amp;amp; v, mat&amp;amp; u) {
    int N = 2;
    mat w(N, vector&amp;lt;int&amp;gt;(N));

    for(int i=0; i&amp;lt;v.size(); i++)
        for(int j=0; j&amp;lt;u[0].size(); j++)
            for(int k=0; k&amp;lt;v[0].size(); k++)
                w[i][j] = (w[i][j] + v[i][k] * u[k][j]) % mod;

    return w;
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    while(T--) {
        int t; cin &amp;gt;&amp;gt; t;

        int N; cin &amp;gt;&amp;gt; N;

        mat mul(2, vector&amp;lt;int&amp;gt;(2));
        for(int i=0; i&amp;lt;2; i++) mul[i][i] = 1;

        mat ba(2, vector&amp;lt;int&amp;gt;(2));
        ba = {{1, 1}, {1, 0}};

        while(N &amp;gt; 0) {
            if(N % 2 == 1) mul = f(mul, ba);

            ba = f(ba, ba);
            N /= 2;
        }

        cout &amp;lt;&amp;lt; t &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; mul[0][1] &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/알고리즘 공부 내용 정리</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/609</guid>
      <comments>https://restudycafe.tistory.com/609#entry609comment</comments>
      <pubDate>Tue, 16 Aug 2022 10:39:33 +0900</pubDate>
    </item>
    <item>
      <title>최소 스패닝 트리, 크루스칼 알고리즘 풀이 모음 220814</title>
      <link>https://restudycafe.tistory.com/608</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 1185번 : 유럽여행&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum IV&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;최소 스패닝 트리&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(MST)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리 형태의 그래프가 주어지고, 한 지점에서 시작하여 어떤 노드와 간선을 지나갈 때의 비용이 모두 주어질 때, 최소 비용으로 모든 노드를 순회할 때 드는 최소 비용을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;경로를 생각해보면, 시작점을 제외하고 어떤 경로든 지나갔다가 다시 돌아와야 하므로, 간선의 시작점 &amp;rarr; 간선 &amp;rarr; 간선의 끝 점 &amp;rarr; 간선 순서로 반드시 지나가게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 간선의 비용 자체를 (간선의 시작점의 비용 + 간선의 끝 점의 비용 + 간선의 비용 x 2)로 설정해주고, 여기에 시작점으로 설정할 최소 비용인 노드의 비용을 더해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660626380507&quot; class=&quot;arduino&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { int a, b, c; };

bool cmp(s x, s y) { return x.c &amp;lt; y.c; }

vector&amp;lt;int&amp;gt; v;

int f(int x) {
    if(v[x] == x) return x;
    else return v[x] = f(v[x]);
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    vector&amp;lt;int&amp;gt; u(N+1);
    int Min = INT_MAX;
    for(int i=1; i&amp;lt;=N; i++) {
        cin &amp;gt;&amp;gt; u[i];

        Min = min(Min, u[i]);
    }

    vector&amp;lt;s&amp;gt; adj(M);

    for(int i=0; i&amp;lt;M; i++) {
        int a, b, c; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b &amp;gt;&amp;gt; c;

        adj[i] = {a, b, c*2 + u[a] + u[b]};
    }

    sort(adj.begin(), adj.end(), cmp);

    v.resize(N+1);
    for(int i=1; i&amp;lt;=N; i++) v[i] = i;

    int ans = 0, cnt = 0;

    for(int i=0; i&amp;lt;adj.size(); i++) {
        int a = adj[i].a, b = adj[i].b, c = adj[i].c;

        if(f(a) == f(b)) continue;

        v[f(a)] = f(b);

        ans += c;
        cnt++;

        if(cnt == N-1) break;
    }

    ans += Min;

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 2887번 : 행성 터널&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Platinum V&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;최소 스패닝 트리&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(MST)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3차원 공간 상에 N개의 점이 있고, 두 점 사이를 연결하는 비용이 min(|xA-xB|, |yA-yB|, |zA-zB|)이라고 할 때, 모든 점들을 서로 연결하기 위한 최소 비용을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최소 스패닝 트리 문제임을 바로 알 수 있지만, N이 최대 10만이므로 가능한 모든 비용을 설정하는 것은 불가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 x, y, z 값들을 각각 정렬해주고, 인접하지 않은 두 값은 어차피 최소가 될 수 없으므로 인접한 N-1쌍들을 adj 벡터에 넣어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, adj 벡터에는 (N-1) x 3개의 값들이 들어가는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 adj 벡터를 정렬해준 뒤 크루스칼 알고리즘을 수행해주면 O(N) 시간에 MST를 찾을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 종합적인 시간 복잡도는 정렬을 수행했으므로 O(N log N)이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660626380510&quot; class=&quot;arduino&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { int a, b, c; };

bool cmp(s x, s y) { return x.c &amp;lt; y.c; }

vector&amp;lt;int&amp;gt; v;

int f(int x) {
    if(v[x] == x) return x;
    else return v[x] = f(v[x]);
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;pair&amp;lt;int, int&amp;gt;&amp;gt; vx(N+1), vy(N+1), vz(N+1);

    for(int i=1; i&amp;lt;=N; i++) {
        cin &amp;gt;&amp;gt; vx[i].first &amp;gt;&amp;gt; vy[i].first &amp;gt;&amp;gt; vz[i].first;

        vx[i].second = vy[i].second = vz[i].second = i;
    }

    sort(vx.begin()+1, vx.end());
    sort(vy.begin()+1, vy.end());
    sort(vz.begin()+1, vz.end());

    vector&amp;lt;s&amp;gt; adj;

    for(int i=2; i&amp;lt;=N; i++) adj.push_back({vx[i-1].second, vx[i].second, vx[i].first - vx[i-1].first});
    for(int i=2; i&amp;lt;=N; i++) adj.push_back({vy[i-1].second, vy[i].second, vy[i].first - vy[i-1].first});
    for(int i=2; i&amp;lt;=N; i++) adj.push_back({vz[i-1].second, vz[i].second, vz[i].first - vz[i-1].first});

    sort(adj.begin(), adj.end(), cmp);

    v.resize(N+1);
    for(int i=1; i&amp;lt;=N; i++) v[i] = i;

    int ans = 0, cnt = 0;

    for(int i=0; i&amp;lt;adj.size(); i++) {
        int a = adj[i].a, b = adj[i].b, c = adj[i].c;

        if(f(a) == f(b)) continue;

        v[f(a)] = f(b);

        ans += c;
        cnt++;

        if(cnt == N-1) break;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 6091번 : 핑크 플로이드&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;최소 스패닝 트리&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(MST)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리에서 플로이드-와셜 알고리즘으로 구한 노드-노드 사이의 최단 거리가 주어졌을 때, 각 노드에 인접해있는 노드들의 목록을 구하는 문제이다. (즉, 트리를 복원하면 된다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 거리들을 정렬했을 때 최단 거리는 무조건 인접한 노드 사이의 간선이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 거리들을 정렬한 뒤 짧은 거리부터 분리 집합을 활용하여 그룹으로 묶어가면서 확인해보면 된다. (두 노드가 같은 그룹이 아닐 경우 서로 인접하다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660626380513&quot; class=&quot;arduino&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { int a, b, c; };

bool cmp(s x, s y) { return x.c &amp;lt; y.c; }

vector&amp;lt;int&amp;gt; v;

int f(int x) {
    if(v[x] == x) return x;
    else return v[x] = f(v[x]);
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;s&amp;gt; adj;

    for(int i=1; i&amp;lt;=N; i++)
        for(int j=i+1; j&amp;lt;=N; j++) {
            int x; cin &amp;gt;&amp;gt; x;

            adj.push_back({i, j, x});
        }

    sort(adj.begin(), adj.end(), cmp);

    v.resize(N+1);
    for(int i=1; i&amp;lt;=N; i++) v[i] = i;

    vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; u(N+1);

    for(int i=0; i&amp;lt;adj.size(); i++) {
        int a = adj[i].a, b = adj[i].b;

        if(f(a) == f(b)) continue;

        u[a].push_back(b);
        u[b].push_back(a);

        v[f(a)] = f(b);
    }

    for(int i=1; i&amp;lt;=N; i++) {
        sort(u[i].begin(), u[i].end());

        cout &amp;lt;&amp;lt; u[i].size() &amp;lt;&amp;lt; &quot; &quot;;

        for(int j=0; j&amp;lt;u[i].size(); j++) cout &amp;lt;&amp;lt; u[i][j] &amp;lt;&amp;lt; &quot; &quot;;

        cout &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 1368번 : 물대기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;최소 스패닝 트리&lt;/span&gt; (MST)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 논이 있는데 각 논에 서로 다른 비용을 들여 우물을 파도 되고, 또는 N x N 행렬로 a_ij = (i번째 논에서 j번째 논에 물을 끌어오는데 필요한 비용)이 주어질 때 모든 논에 물을 들이기 위해 필요한 최소 비용을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 생각해볼 수 있는 것은 여러 개의 부분 그래프를 만들고 각 부분 그래프에서 우물을 파는 가장 작은 비용을 골라 답에 합산하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 이렇게 구현할 경우 부분 그래프를 어떻게 연결할지가 결정되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 문제의 경우 &lt;span style=&quot;color: #ee2323;&quot;&gt;0번 노드를 하나 만들어서 i번 논에 우물을 파는 비용을 0번 노드와 i번 노드를 연결하는 간선의 비용으로 설정해주고, 0 ~ N번 노드에 대한 최소 스패닝 트리의 비용을 구해주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 구현할 경우 문제에서 요구하는 조건과 완전히 대응되는 그래프가 얻어진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660484409546&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { int a, b, c; };

bool cmp(s x, s y) { return x.c &amp;lt; y.c; }

vector&amp;lt;int&amp;gt; v;

int f(int x) {
    if(v[x] == x) return x;
    else return v[x] = f(v[x]);
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;s&amp;gt; adj;

    for(int i=1; i&amp;lt;=N; i++) {
        int x; cin &amp;gt;&amp;gt; x;

        adj.push_back({0, i, x});
    }

    for(int i=1; i&amp;lt;=N; i++)
        for(int j=1; j&amp;lt;=N; j++) {
            int x; cin &amp;gt;&amp;gt; x;

            if(i &amp;gt;= j) continue;

            adj.push_back({i, j, x});
        }

    sort(adj.begin(), adj.end(), cmp);

    v.resize(N+1);
    for(int i=0; i&amp;lt;=N; i++) v[i] = i;

    int ans = 0, cnt = 0;

    for(int i=0; i&amp;lt;adj.size(); i++) {
        int a = adj[i].a, b = adj[i].b, c = adj[i].c;

        if(f(a) == f(b)) continue;

        v[f(a)] = f(b);

        ans += c;
        cnt++;

        if(cnt == N) break;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 23743번 : 방탈출&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;최소 스패닝 트리&lt;/span&gt; (MST)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 문제와 동일한 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비용의 개념이 시간의 개념으로 바뀌긴 했지만 풀이도 같으며, 코드 또한 똑같이 구현해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여담으로 이 문제의 기존 난이도가 &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold III&lt;/b&gt;&lt;/span&gt;이었는데 난이도 기여를 하여 &lt;b&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;Gold II&lt;/span&gt;&lt;/b&gt;로 상향 조정되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660484758108&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { int a, b, c; };

bool cmp(s x, s y) { return x.c &amp;lt; y.c; }

vector&amp;lt;int&amp;gt; v;

int f(int x) {
    if(v[x] == x) return x;
    else return v[x] = f(v[x]);
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    vector&amp;lt;s&amp;gt; adj;

    while(M--) {
        int a, b, c; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b &amp;gt;&amp;gt; c;

        adj.push_back({a, b, c});
    }

    for(int i=1; i&amp;lt;=N; i++) {
        int x; cin &amp;gt;&amp;gt; x;

        adj.push_back({0, i, x});
    }

    sort(adj.begin(), adj.end(), cmp);

    v.resize(N+1);
    for(int i=0; i&amp;lt;=N; i++) v[i] = i;

    int ans = 0, cnt = 0;

    for(int i=0; i&amp;lt;adj.size(); i++) {
        int a = adj[i].a, b = adj[i].b, c = adj[i].c;

        if(f(a) == f(b)) continue;

        v[f(a)] = f(b);

        ans += c;
        cnt++;

        if(cnt == N) break;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 20335번 : Generators&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold I&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;최소 스패닝 트리&lt;/span&gt; (MST)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 섬이 있고 그들 중 M개는 발전소 설치 후보일 때, M개의 줄에 걸쳐 섬의 번호와 설치 비용이 주어지고, N개의 정수 a_i = i번 섬과 i+1번 섬을 연결하는 비용이 주어질 때, 모든 섬들에 전력을 공급하기 위한 최소 비용을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제 역시 위의 문제와 동일하지만, 이 문제의 경우에는 대놓고 그래프를 떠올릴 수 있는 문제는 아니므로 위의 문제를 이해하고 풀이하는 것이 수월하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;발전소 설치 = 0번 노드와의 연결&quot;이라고 생각하고, 0 ~ N번 노드들에 대한 최소 스패닝 트리의 비용을 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660486251260&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { int a, b, c; };

bool cmp(s x, s y) { return x.c &amp;lt; y.c; }

vector&amp;lt;int&amp;gt; v;

int f(int x) {
    if(v[x] == x) return x;
    else return v[x] = f(v[x]);
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    vector&amp;lt;s&amp;gt; adj;

    while(M--) {
        int a, b; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;

        adj.push_back({0, a, b});
    }

    for(int i=1; i&amp;lt;=N; i++) {
        int x; cin &amp;gt;&amp;gt; x;

        if(i != N) adj.push_back({i, i+1, x});
        else adj.push_back({N, 1, x});
    }

    sort(adj.begin(), adj.end(), cmp);

    v.resize(N+1);
    for(int i=0; i&amp;lt;=N; i++) v[i] = i;

    int ans = 0, cnt = 0;

    for(int i=0; i&amp;lt;adj.size(); i++) {
        int a = adj[i].a, b = adj[i].b, c = adj[i].c;

        if(f(a) == f(b)) continue;

        v[f(a)] = f(b);

        ans += c;
        cnt++;

        if(cnt == N) break;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 10423번 : 전기가 부족해&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;최소 스패닝 트리&lt;/span&gt; (MST)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 노드와 M개의 간선이 있는 그래프가 주어지고, K개의 노드는 이미 발전소가 설치되어 있다고 할 때, 적절한 간선들을 선택하여 모든 노드에 전기가 통하도록 하는 최소 비용을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 문제들과 비슷한 방식으로, 0번 노드를 가상으로 만들어 K개의 발전소 노드들과 연결하고 N개의 간선을 갖는 N+1 노드들의 최소 스패닝 트리를 구성하는 최소 비용을 크루스칼 알고리즘으로 구현해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660488154859&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { int a, b, c; };

bool cmp(s x, s y) { return x.c &amp;lt; y.c; }

vector&amp;lt;int&amp;gt; v;

int f(int x) {
    if(v[x] == x) return x;
    else return v[x] = f(v[x]);
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M, K; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M &amp;gt;&amp;gt; K;

    vector&amp;lt;s&amp;gt; adj;

    while(K--) {
        int x; cin &amp;gt;&amp;gt; x;

        adj.push_back({0, x, 0});
    }

    while(M--) {
        int a, b, c; cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b &amp;gt;&amp;gt; c;

        adj.push_back({a, b, c});
    }

    sort(adj.begin(), adj.end(), cmp);

    v.resize(N+1);
    for(int i=1; i&amp;lt;=N; i++) v[i] = i;

    int ans = 0, cnt = 0;

    for(int i=0; i&amp;lt;adj.size(); i++) {
        int a = adj[i].a, b = adj[i].b, c = adj[i].c;

        if(f(a) == f(b)) continue;

        v[f(a)] = f(b);

        ans += c;
        cnt++;

        if(cnt == N) break;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 5818번 : SPIJUNI&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;최소 스패닝 트리&lt;/span&gt; (MST)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N x N 행렬로 a_ij = i번째 스파이가 j번째 스파이에게 정보를 전달하는 비용이 주어지고, 마지막 줄에 주어지는 N개의 값에 대해 b_i = i번째 스파이에게 정보를 최초로 전달하는데 필요한 비용이 있다면, 모든 스파이에게 정보를 전달하는데 필요한 최소 비용을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역시 마찬가지로 최초로 정보를 전달하는 곳을 0번 노드라고 생각하고 간선들을 이은 뒤, N+1개의 노드에 대해 최소 스패닝 트리의 비용을 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660486778856&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { int a, b, c; };

bool cmp(s x, s y) { return x.c &amp;lt; y.c; }

vector&amp;lt;int&amp;gt; v;

int f(int x) {
    if(v[x] == x) return x;
    else return v[x] = f(v[x]);
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;s&amp;gt; adj;

    for(int i=1; i&amp;lt;=N; i++)
        for(int j=1; j&amp;lt;=N; j++) {
            int x; cin &amp;gt;&amp;gt; x;

            if(i &amp;gt;= j) continue;

            adj.push_back({i, j, x});
        }

    for(int i=1; i&amp;lt;=N; i++) {
        int x; cin &amp;gt;&amp;gt; x;

        adj.push_back({0, i, x});
    }

    sort(adj.begin(), adj.end(), cmp);

    v.resize(N+1);
    for(int i=0; i&amp;lt;=N; i++) v[i] = i;

    int ans = 0, cnt = 0;

    for(int i=0; i&amp;lt;adj.size(); i++) {
        int a = adj[i].a, b = adj[i].b, c = adj[i].c;

        if(f(a) == f(b)) continue;

        v[f(a)] = f(b);

        ans += c;
        cnt++;

        if(cnt == N) break;
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 10661번 : Median Tree&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;b&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;Gold II&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;최소 스패닝 트리&lt;/span&gt; (MST)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 노드와 M개의 간선을 가지는 그래프가 주어질 때, 이들 중 N-1개의 간선을 선택하여 트리를 만들 때, N-1개의 간선들 중 중앙값이 최소가 되는 트리에서 중앙값을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;크루스칼 알고리즘을 기본적으로 이해하고 있다면 문제의 의도를 파악할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애초에 MST를 구하는 크루스칼 알고리즘은 가장 낮은 비용의 간선부터 검사하면서 트리에 추가하기 때문에, 결국에는 최소 스패닝 트리를 구했을 때 간선들의 중앙값이 최소가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 최소 스패닝 트리를 구하면서 N/2번째로 추가된 간선을 답으로 구해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660488603075&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { int a, b, c; };

bool cmp(s x, s y) { return x.c &amp;lt; y.c; }

vector&amp;lt;int&amp;gt; v;

int f(int x) {
    if(v[x] == x) return x;
    else return v[x] = f(v[x]);
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    while(true) {
        int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;
        if(N == 0 &amp;amp;&amp;amp; M == 0) break;

        vector&amp;lt;s&amp;gt; adj(M);

        for(int i=0; i&amp;lt;M; i++)
            cin &amp;gt;&amp;gt; adj[i].a &amp;gt;&amp;gt; adj[i].b &amp;gt;&amp;gt; adj[i].c;

        sort(adj.begin(), adj.end(), cmp);

        v.resize(N+1);
        for(int i=1; i&amp;lt;=N; i++) v[i] = i;

        int ans = 0, cnt = 0;

        for(int i=0; i&amp;lt;adj.size(); i++) {
            int a = adj[i].a, b = adj[i].b, c = adj[i].c;

            if(f(a) == f(b)) continue;

            v[f(a)] = f(b);

            cnt++;

            if(cnt == N/2) ans = c;
            if(cnt == N-1) break;
        }

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 20757번 : Roadside optimization&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;분리 집합&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;크기가 N x N인 인접 행렬이 주어졌을 때 해당 형태의 그래프를 만들기 위해서 필요한 최소 간선의 수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분리 집합을 이용하여 몇 개의 그룹이 존재하는지를 찾으면, N - (그룹의 개수)가 필요한 최소 간선의 수가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660481452085&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

vector&amp;lt;int&amp;gt; v;

int f(int x) {
    if(v[x] == x) return x;
    else return v[x] = f(v[x]);
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    while(T--) {
        int N; cin &amp;gt;&amp;gt; N;

        v.clear();
        v.resize(N+1);
        for(int i=1; i&amp;lt;=N; i++) v[i] = i;

        for(int i=1; i&amp;lt;=N; i++)
            for(int j=1; j&amp;lt;=N; j++) {
                int x; cin &amp;gt;&amp;gt; x;

                if(i &amp;gt;= j || x == 0) continue;

                if(f(i) == f(j)) continue;

                v[f(i)] = f(j);
            }

        vector&amp;lt;int&amp;gt; u;
        for(int i=1; i&amp;lt;=N; i++) u.push_back(f(i));

        sort(u.begin(), u.end());
        u.erase(unique(u.begin(), u.end()), u.end());

        int ans = N - u.size();

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 16393번 : Lost Map&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;최소 스패닝 트리&lt;/span&gt; (MST)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N x N 크기의 행렬이 주어지고 a_ij = i번 마을에서 j번 마을로 가는 도로의 거리라고 할 때, 최소 비용으로 모든 도로를 연결해야 한다면 연결해야 하는 도로들의 목록(양 끝 마을)을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;크루스칼 알고리즘을 활용하여 최소 스패닝 트리를 찾으면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여담으로 다른 MST 문제들과 비교해 보았을 때 난이도가 높게 책정되어 있다고 생각하여 난이도 기여로 &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold III&lt;/b&gt;&lt;/span&gt;으로 투표했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660489584961&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { int a, b, c; };

bool cmp(s x, s y) { return x.c &amp;lt; y.c; }

vector&amp;lt;int&amp;gt; v;

int f(int x) {
    if(v[x] == x) return x;
    else return v[x] = f(v[x]);
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin &amp;gt;&amp;gt; N;

    vector&amp;lt;s&amp;gt; adj;

    for(int i=1; i&amp;lt;=N; i++)
        for(int j=1; j&amp;lt;=N; j++) {
            int x; cin &amp;gt;&amp;gt; x;

            if(i &amp;gt;= j) continue;

            adj.push_back({i, j, x});
        }

    sort(adj.begin(), adj.end(), cmp);

    v.resize(N+1);
    for(int i=1; i&amp;lt;=N; i++) v[i] = i;

    int ans = 0, cnt = 0;
    vector&amp;lt;pair&amp;lt;int, int&amp;gt;&amp;gt; u;

    for(int i=0; i&amp;lt;adj.size(); i++) {
        int a = adj[i].a, b = adj[i].b, c = adj[i].c;

        if(f(a) == f(b)) continue;

        v[f(a)] = f(b);

        ans += c;
        cnt++;

        u.push_back({a, b});

        if(cnt == N-1) break;
    }

    for(int i=0; i&amp;lt;u.size(); i++)
        cout &amp;lt;&amp;lt; u[i].first &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; u[i].second &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 20010번 : 악덕 영주 혜유&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold II&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;최소 스패닝 트리&lt;/span&gt; (MST), &lt;span style=&quot;color: #ee2323;&quot;&gt;트리의 지름&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래프가 주어질 때, 이들 중 일부 간선을 선택하여 연결 비용이 최소가 되도록 할 때 이 때의 비용과 가장 거리가 먼 두 노드 사이의 거리를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 모든 노드들을 연결 비용이 최소가 되도록 하는 것은 최소 스패닝 트리를 찾으라는 것과 같으므로, 크루스칼 알고리즘으로 풀어주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이 그래프에서 가장 거리가 먼 두 점 사이의 거리라는 것은 트리의 지름을 의미하는 것이므로, 선택된 간선들을 추가하여 그래프를 다시 구성해준 뒤, 이 그래프에서 트리의 지름을 찾는 DFS 탐색을 수행해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리의 지름을 찾는 코드는 &lt;b&gt;백준 BOJ 1167번 : 트리의 지름&lt;/b&gt; 문제를 참고하면 도움이 될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660490645447&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { int a, b, c; };

bool cmp(s x, s y) { return x.c &amp;lt; y.c; }

vector&amp;lt;int&amp;gt; v;

int f(int x) {
    if(v[x] == x) return x;
    else return v[x] = f(v[x]);
}

vector&amp;lt;vector&amp;lt;pair&amp;lt;int, int&amp;gt;&amp;gt;&amp;gt; ad;
int Max = 0, node = 0;

void g(int cur, int pre, int sum) {
    if(sum &amp;gt; Max) {
        Max = sum;
        node = cur;
    }

    for(int i=0; i&amp;lt;ad[cur].size(); i++)
        if(ad[cur][i].first != pre) g(ad[cur][i].first, cur, sum + ad[cur][i].second);
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    vector&amp;lt;s&amp;gt; adj(M);

    for(int i=0; i&amp;lt;M; i++)
        cin &amp;gt;&amp;gt; adj[i].a &amp;gt;&amp;gt; adj[i].b &amp;gt;&amp;gt; adj[i].c;

    sort(adj.begin(), adj.end(), cmp);

    v.resize(N);
    for(int i=0; i&amp;lt;N; i++) v[i] = i;

    int ans = 0, cnt = 0;
    vector&amp;lt;s&amp;gt; u;

    for(int i=0; i&amp;lt;adj.size(); i++) {
        int a = adj[i].a, b = adj[i].b, c = adj[i].c;

        if(f(a) == f(b)) continue;

        v[f(a)] = f(b);

        ans += c;
        cnt++;

        u.push_back({a, b, c});

        if(cnt == N-1) break;
    }

    ad.resize(N);

    for(int i=0; i&amp;lt;u.size(); i++) {
        int a = u[i].a, b = u[i].b, c = u[i].c;

        ad[a].push_back({b, c});
        ad[b].push_back({a, c});
    }

    g(0, -1, 0);

    Max = 0;

    g(node, -1, 0);

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot; &amp;lt;&amp;lt; Max &amp;lt;&amp;lt; &quot;\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 22813번 : Building a Space Station&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;최소 스패닝 트리&lt;/span&gt; (MST)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3차원 공간 상에 N개의 구가 있고, 접하거나 겹치지 않는 구들에 대해 구의 표면과 표면 사이를 연결하여 모든 구들을 연결할 때, 필요한 길이의 최솟값을 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3차원 공간 상에서 최소 스패닝 트리를 그대로 구현해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구가 만약 접하거나 겹친다면 비용이 0인 간선으로 처리해주고, 그렇지 않은 경우 두 구의 중심 사이의 거리에서 두 구의 반지름의 합을 빼주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660482162708&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { double a, b, c; };
struct ss { double x, y, z, r; };

bool cmp(s x, s y) { return x.c &amp;lt; y.c; }

vector&amp;lt;int&amp;gt; v;

int f(int x) {
    if(v[x] == x) return x;
    else return v[x] = f(v[x]);
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    cout &amp;lt;&amp;lt; fixed;
    cout.precision(3);

    while(true) {
        int N; cin &amp;gt;&amp;gt; N;
        if(N == 0) break;

        vector&amp;lt;ss&amp;gt; u(N+1);
        for(int i=1; i&amp;lt;=N; i++)
            cin &amp;gt;&amp;gt; u[i].x &amp;gt;&amp;gt; u[i].y &amp;gt;&amp;gt; u[i].z &amp;gt;&amp;gt; u[i].r;

        vector&amp;lt;s&amp;gt; adj;

        for(int i=1; i&amp;lt;=N; i++)
            for(int j=i+1; j&amp;lt;=N; j++) {
                double d = sqrt(pow(u[i].x - u[j].x, 2) + pow(u[i].y - u[j].y, 2) + pow(u[i].z - u[j].z, 2));

                if(d &amp;lt;= u[i].r + u[j].r) adj.push_back({i, j, 0});
                else adj.push_back({i, j, d - (u[i].r + u[j].r)});
            }

        sort(adj.begin(), adj.end(), cmp);

        v.clear();
        v.resize(N+1);
        for(int i=1; i&amp;lt;=N; i++) v[i] = i;

        double ans = 0, cnt = 0;

        for(int i=0; i&amp;lt;adj.size(); i++) {
            double a = adj[i].a, b = adj[i].b, c = adj[i].c;

            if(f(a) == f(b)) continue;

            v[f(a)] = f(b);

            ans += c;
            cnt++;

            if(cnt == N-1) break;
        }

        cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;백준 BOJ 23941번 : Cherries Mesh&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 난이도 : &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;Gold III&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 분류 : &lt;span style=&quot;color: #ee2323;&quot;&gt;최소 스패닝 트리&lt;/span&gt; (MST), &lt;span style=&quot;color: #ee2323;&quot;&gt;분리 집합&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 체리가 M개의 검은 설탕으로 연결되어 있고, 나머지 두 체리 쌍들에 대해서는 빨간 설탕으로 연결되어 있으며 검은 설탕은 1의 당도이고 빨간 설탕은 2의 당도라면 일부 설탕을 제거하여 모든 체리를 연결하는 최소 당도를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 최소 스패닝 트리를 만드는 문제이고, 검은 설탕의 당도가 더 작으므로 검은 설탕을 최대한 간선으로 구성해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게 때문에 &lt;span style=&quot;color: #ee2323;&quot;&gt;분리 집합을 활용하여 사이클이 생기지 않는 선에서 M개의 검은 설탕 간선으로 노드들을 최대한 연결&lt;/span&gt;해주고, 최종적으로 K개의 부분 그래프(트리)가 만들어졌다면 이들은 K-1개의 빨간 설탕으로 연결이 가능하므로 답에 (K-1) * 2를 더해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660483515686&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define int long long
using namespace std;

struct s { int a, b, c; };

bool cmp(s x, s y) { return x.c &amp;lt; y.c; }

vector&amp;lt;int&amp;gt; v;

int f(int x) {
    if(v[x] == x) return x;
    else return v[x] = f(v[x]);
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin &amp;gt;&amp;gt; T;

    for(int t=1; t&amp;lt;=T; t++) {
        int N, M; cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

        vector&amp;lt;s&amp;gt; adj(M);

        for(int i=0; i&amp;lt;M; i++) {
            cin &amp;gt;&amp;gt; adj[i].a &amp;gt;&amp;gt; adj[i].b;

            adj[i].c = 1;
        }

        sort(adj.begin(), adj.end(), cmp);

        v.resize(N+1);
        for(int i=1; i&amp;lt;=N; i++) v[i] = i;

        int ans = 0, cnt = 0;

        for(int i=0; i&amp;lt;adj.size(); i++) {
            int a = adj[i].a, b = adj[i].b, c = adj[i].c;

            if(f(a) == f(b)) continue;

            v[f(a)] = f(b);

            ans += c;
            cnt++;

            if(cnt == N-1) break;
        }

        vector&amp;lt;int&amp;gt; u;
        for(int i=1; i&amp;lt;=N; i++) u.push_back(f(i));

        sort(u.begin(), u.end());
        u.erase(unique(u.begin(), u.end()), u.end());

        ans += (u.size() - 1) * 2;

        cout &amp;lt;&amp;lt; &quot;Case #&quot; &amp;lt;&amp;lt; t &amp;lt;&amp;lt; &quot;: &quot; &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; &quot;\n&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/백준(BOJ) 문제풀이</category>
      <author>restudy</author>
      <guid isPermaLink="true">https://restudycafe.tistory.com/608</guid>
      <comments>https://restudycafe.tistory.com/608#entry608comment</comments>
      <pubDate>Sun, 14 Aug 2022 22:49:37 +0900</pubDate>
    </item>
  </channel>
</rss>