<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>passionfruit200</title>
    <link>https://passionfruit200.tistory.com/</link>
    <description>passionfruit200 의 블로그입니다.</description>
    <language>ko</language>
    <pubDate>Thu, 7 May 2026 14:14:49 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>passionfruit200</managingEditor>
    <image>
      <title>passionfruit200</title>
      <url>https://tistory1.daumcdn.net/tistory/5106881/attach/fc72efa09bc345d2b277934a28ad6a5d</url>
      <link>https://passionfruit200.tistory.com</link>
    </image>
    <item>
      <title>[백준] 9177 단어 섞기 - 깊이우선탐색(DFS) + 동적계획법(DP) JAVA</title>
      <link>https://passionfruit200.tistory.com/1728</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/9177&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/9177&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;코드설명&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;먼저 이 문제는 깊이우선탐색으로 풀 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;각 단어의 인덱스를 관리하면서 C가 마지막 길이까지 가면 성공한 것입니다.&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 data-ke-size=&quot;size16&quot;&gt;처음에는 시간복잡도 고려하지 않고 접근했고, 시간초과가 발생했습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;시간복잡도는 최악의 경우 400^2 입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1766420201284&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class Main {
    static int N;
    static String A, B, C;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        N = Integer.parseInt(st.nextToken());

        for(int i=0; i&amp;lt;N; i++){
            st = new StringTokenizer(br.readLine());
            A = st.nextToken();
            B = st.nextToken();
            C = st.nextToken();
            
            System.out.println(&quot;Data set &quot;+ (i+1)+&quot;: &quot;+ ( solve(0, 0, 0) ? &quot;yes&quot; : &quot;no&quot;) );
        }
        
    }

    static boolean solve(int a_idx, int b_idx, int c_idx){
    	if(c_idx == C.length()) {
    		return true;
    	}
    	
    	boolean ret = false;
        if(a_idx &amp;lt; A.length() &amp;amp;&amp;amp; C.charAt(c_idx) == A.charAt(a_idx) ) {
        	ret |= solve(a_idx + 1, b_idx, c_idx + 1);
        }
        if(b_idx &amp;lt; B.length() &amp;amp;&amp;amp; C.charAt(c_idx) == B.charAt(b_idx)) {
        	ret |= solve(a_idx, b_idx + 1, c_idx + 1);
        }
        
        return ret;
    }


}&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;pre id=&quot;code_1766420247033&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package Main;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class Main {
    static int N;
    static String A, B, C;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        N = Integer.parseInt(st.nextToken());

        for(int i=0; i&amp;lt;N; i++){
            st = new StringTokenizer(br.readLine());
            A = st.nextToken();
            B = st.nextToken();
            C = st.nextToken();
            
            for(int j=0; j&amp;lt;205; j++) {
            	for(int k=0; k&amp;lt;205; k++) {
            		Arrays.fill(dp[j][k], -1);
            	}
            }
            System.out.println(&quot;Data set &quot;+ (i+1)+&quot;: &quot;+ ( solve(0, 0, 0) ? &quot;yes&quot; : &quot;no&quot;) );
        }
        
    }
    
    static int[][][] dp = new int[205][205][410];
    static boolean solve(int a_idx, int b_idx, int c_idx){
    	if(dp[a_idx][b_idx][c_idx] == 1) return true;
    	else if(dp[a_idx][b_idx][c_idx] == 0) return false;
    	
    	if(c_idx == C.length()) {
    		return true;
    	}
    	
    	boolean ret = false;
        if(a_idx &amp;lt; A.length() &amp;amp;&amp;amp; C.charAt(c_idx) == A.charAt(a_idx) ) {
        	ret |= solve(a_idx + 1, b_idx, c_idx + 1);
        }
        if(b_idx &amp;lt; B.length() &amp;amp;&amp;amp; C.charAt(c_idx) == B.charAt(b_idx)) {
        	ret |= solve(a_idx, b_idx + 1, c_idx + 1);
        }
        
    	dp[a_idx][b_idx][c_idx] = ret ? 1 : 0;
        return ret;
    }


}&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;하지만, 좀 더 최적화시키면, 애초에 c_idx가 필요하지 않는걸 알 수 있습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;코드&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;c_idx는 a_idx + b_idx로 찾아냅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좀 찜찜한점은, 목표 String이 전역적으로 선언되어있어 solve 함수내에서 참조되고 있기에 dp[A String][B String]으로만 충분한지 고민되지만, A, B, C의 변수값이 가변적이지 않기에 상관없습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1766420420401&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package Main;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class Main {
    static int N;
    static String A, B, C;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        N = Integer.parseInt(st.nextToken());

        for(int i=0; i&amp;lt;N; i++){
            st = new StringTokenizer(br.readLine());
            A = st.nextToken();
            B = st.nextToken();
            C = st.nextToken();
            
            for(int j=0; j&amp;lt;205; j++) {
        		Arrays.fill(dp[j], -1);
            }
            System.out.println(&quot;Data set &quot;+ (i+1)+&quot;: &quot;+ ( solve(0, 0) ? &quot;yes&quot; : &quot;no&quot;) );
        }
        
    }
    
    static int[][] dp = new int[205][205];
//    현재 A의 앞 a_idx 글자, B의 앞 b_idx의 글자를 이미 사용했을떄 C의 앞글자를 만들 수 있는지를 반환하는 함수
    static boolean solve(int a_idx, int b_idx){
    	if(dp[a_idx][b_idx] == 1) return true;
    	else if(dp[a_idx][b_idx] == 0) return false;
    	
    	if((a_idx + b_idx) == C.length()) {
    		return true;
    	}
    	
    	boolean ret = false;
        if(a_idx &amp;lt; A.length() &amp;amp;&amp;amp; C.charAt(a_idx + b_idx) == A.charAt(a_idx) ) {
        	ret |= solve(a_idx + 1, b_idx);
        }
        if(b_idx &amp;lt; B.length() &amp;amp;&amp;amp; C.charAt(a_idx + b_idx) == B.charAt(b_idx)) {
        	ret |= solve(a_idx, b_idx + 1);
        }
        
    	dp[a_idx][b_idx] = ret ? 1 : 0;
        return ret;
    }


}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/백준</category>
      <author>passionfruit200</author>
      <guid isPermaLink="true">https://passionfruit200.tistory.com/1728</guid>
      <comments>https://passionfruit200.tistory.com/1728#entry1728comment</comments>
      <pubDate>Tue, 23 Dec 2025 01:23:13 +0900</pubDate>
    </item>
    <item>
      <title>[백준][랜덤디펜스] 골랜디 Virtual #4</title>
      <link>https://passionfruit200.tistory.com/1677</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;골랜디&amp;nbsp;Virtual&amp;nbsp;#3&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 : 2/8&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SQL : 3/3&lt;/p&gt;
&lt;h1 style=&quot;background-color: #ffffff; color: #585f69; text-align: start;&quot;&gt;&lt;span&gt;중첩 집합 모델&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/19641&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/19641&lt;/a&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;pre id=&quot;code_1744773628670&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Main {
    static int N, A, B, H, W;
    static int answer = 0;
    static int[] left, right;
    static int timer = 1;
    static ArrayList&amp;lt;Integer&amp;gt;[] adj;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        
        N = Integer.parseInt(st.nextToken());
        adj = new ArrayList[N+1];
        for(int i=1; i&amp;lt;=N; i++) {
        	adj[i] = new ArrayList&amp;lt;&amp;gt;();
        }
        
        for(int i=0; i&amp;lt;N; i++) {
        	st = new StringTokenizer(br.readLine());
        	int node = Integer.parseInt(st.nextToken());
        	while(st.hasMoreTokens()) {
        		int next = Integer.parseInt(st.nextToken());
        		if(next == -1) break;
        		adj[node].add(next);
        	}
        }
        
        st = new StringTokenizer(br.readLine());
        int root = Integer.parseInt(st.nextToken());
        
        for(int i=1; i&amp;lt;=N; i++) {
        	Collections.sort(adj[i]);
        }
        
        left = new int[N+1];
        right = new int[N+1];
        
        //DFS 수행 : 루트노트부터 시작, 부모는 0으로 지정
        dfs(root, 0);
        
        for(int i=1; i&amp;lt;=N; i++) {
        	System.out.println(i + &quot; &quot; + left[i] + &quot; &quot;+ right[i]);
        }
    }
    
    //DFS 함수 : 현재 노드 u, 부모 노드 parent
    static void dfs(int u, int parent) {
    	left[u] = timer++;
    	for(int v : adj[u]) {
    		if(v == parent) continue;
    		dfs(v, u);
    	}
    	right[u] = timer++; 
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1 style=&quot;background-color: #ffffff; color: #585f69; text-align: start;&quot;&gt;&lt;span&gt;팀배분&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/1953&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/1953&lt;/a&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;- 동지의 적은 나의 적이다.&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;이분그래프이므로, 내가 만약 청색팀이라면, 내가 싫어하는 팀은 반드시 백팀입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 활용해서 BFS로 만날때마다 바로바로 반대의 색깔로 칠해주면 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1744773780367&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Main {
    static int N, A, B, H, W;
    static int answer = 0;
    static ArrayList&amp;lt;Integer&amp;gt;[] disLikeList;
    static int[] team;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        
        N = Integer.parseInt(st.nextToken());
        disLikeList = new ArrayList[N+1];
        for(int i=1; i&amp;lt;=N; i++) {
        	disLikeList[i] = new ArrayList&amp;lt;&amp;gt;();
        }
        
        for(int i=1; i&amp;lt;=N; i++) {
        	st = new StringTokenizer(br.readLine());
        	int count = Integer.parseInt(st.nextToken());
        	for(int j=0; j&amp;lt;count; j++) {
        		int disLikedPerson = Integer.parseInt(st.nextToken());
        		disLikeList[i].add(disLikedPerson);
        		disLikeList[disLikedPerson].add(i);
        	}
        }
        
        team = new int[N+1];
        for(int i=1; i&amp;lt;=N; i++) {
        	team[i] = -1;
        }

        for(int i=1; i&amp;lt;=N; i++) {
        	if(team[i] == -1) {
        		bfs(i);
        	}
        }

        //결과를 저장할 리스트
        ArrayList&amp;lt;Integer&amp;gt; blueTeam = new ArrayList&amp;lt;&amp;gt;();
        ArrayList&amp;lt;Integer&amp;gt; whiteTeam = new ArrayList&amp;lt;&amp;gt;();
        
        for(int i=1; i&amp;lt;=N; i++) {
        	if(team[i] == 0) {
        		blueTeam.add(i);
        	} else {
        		whiteTeam.add(i);
        	}
        }
        
        Collections.sort(blueTeam);
        Collections.sort(whiteTeam);
        
        System.out.println(blueTeam.size());
        for(int v : blueTeam) {
        	System.out.print(v+&quot; &quot;);
        }
        System.out.println();
        System.out.println(whiteTeam.size());
        for(int v : whiteTeam) {
        	System.out.print(v+&quot; &quot;);
        }
    }

    //BFS를 통해 이분 그래프 색칠
    static void bfs(int start) {
    	Queue&amp;lt;Integer&amp;gt; q = new LinkedList&amp;lt;&amp;gt;();
    	q.add(start);
    	team[start] = 0;
    	
    	while(!q.isEmpty()) {
    		int here = q.poll();
    		
    		for(int neighbor:disLikeList[here]) {
    			if(team[neighbor] == -1) {
    				team[neighbor] = 1 - team[here];
    				q.add(neighbor);
    			}
    		}
    	}
    	
    }
    
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1 style=&quot;background-color: #ffffff; color: #585f69; text-align: start;&quot;&gt;&lt;span&gt;아기 홍윤&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/24023&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/24023&lt;/a&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;슬라이딩 윈도우로 접근했습니다. 또한 BitWise 연산은 반드시 증가할 수 밖에 없다는점을 유의합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 해당 범위의 BitWise 결과가&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;K보다 크다면, Left로 K보다 작아질떄까지 계속 LEft를 이동시켜주고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;K보다 작다면, 계속해서 right를 증가시키면서 처리하면 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1744773932153&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Main {
    static int N, A, B, H, W, K;
    static int answer = 0;
    static int[] arr;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        
        N = Integer.parseInt(st.nextToken());
        K = Integer.parseInt(st.nextToken());
        arr = new int[N];
        
        st = new StringTokenizer(br.readLine());
        for(int i=0; i&amp;lt;N; i++) {
        	arr[i] = Integer.parseInt(st.nextToken());
        }
        int left = 0;
        int bitWiseRet = 0;
        
        for(int right = 0; right &amp;lt; N; right++) {
        	bitWiseRet |= arr[right];
        	
        	while(left &amp;lt;= right &amp;amp;&amp;amp; bitWiseRet &amp;gt; K) {
        		bitWiseRet = 0;
        		left++;
        		for(int i=left; i&amp;lt;=right; i++) {
        			bitWiseRet |= arr[i];
        		}
        	}
        	
        	if(bitWiseRet == K) {
        		System.out.println((left+1)+&quot; &quot;+(right+1));
        		return ;
        	}
        }
        System.out.println(-1);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1 style=&quot;background-color: #ffffff; color: #585f69; text-align: start;&quot;&gt;&lt;span&gt;게임 오브 데쓰 (Easy)&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/32654&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/32654&lt;/a&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[k][i] : K번쨰 턴에 i번쨰 참가자가 지목될 수 있는지 여부 (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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 K = 10 ~ 99 까지 검사하면서 상윤이가 한번이라도 T인경우가 존재한다면, 그 K값을 반환하면 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1744774028700&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Main {
    static int N, A, B, H, W, K;
    static int answer = -1;
    static int[] arr;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        
        N = Integer.parseInt(st.nextToken());
        int[] L = new int[N + 1];
        int[] R = new int[N + 1];
        
        for (int i = 1; i &amp;lt;= N; i++) {
        	st = new StringTokenizer(br.readLine());
            L[i] = Integer.parseInt(st.nextToken());
            R[i] = Integer.parseInt(st.nextToken());
        }
        
        int maxK = 99;
        // dp[k][i] : k번 전달 후 i번 참가자가 차례를 받을 수 있는지 여부
        boolean[][] dp = new boolean[maxK + 1][N + 1];
        dp[0][1] = true; 
        
        for (int step = 0; step &amp;lt; maxK; step++) {
            for (int i = 1; i &amp;lt;= N; i++) {
                if (dp[step][i]) {
                    dp[step + 1][L[i]] = true;
                    dp[step + 1][R[i]] = true;
                }
            }
        }
        
        int answer = -1;
        for (int k = 10; k &amp;lt;= 99; k++) {
            if (!dp[k][1]) {
                answer = k;
                break;
            }
        }
        
        System.out.println(answer);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;a style=&quot;background-color: #f0f0f0; color: #000000; text-align: start;&quot; href=&quot;https://leetcode.com/problems/queries-quality-and-percentage/&quot;&gt;1211. Queries Quality and Percentage&lt;/a&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/queries-quality-and-percentage/?envType=study-plan-v2&amp;amp;envId=top-sql-50&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/queries-quality-and-percentage/?envType=study-plan-v2&amp;amp;envId=top-sql-50&lt;/a&gt;&lt;/p&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 BY 한 이후의 테이블을 예측하고, 각 집계함수를 적용하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1744774107413&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/* Write your PL/SQL query statement below */

SELECT Q.QUERY_NAME, ROUND(SUM(Q.RATING/Q.POSITION) / COUNT(Q.QUERY_NAME), 2) AS QUALITY, 
    ROUND(SUM(CASE 
            WHEN RATING &amp;lt; 3 THEN 1
            ELSE 0
        END) / COUNT(Q.QUERY_NAME) * 100, 2) AS POOR_QUERY_PERCENTAGE
FROM QUERIES Q
GROUP BY Q.QUERY_NAME&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;a style=&quot;background-color: #f0f0f0; color: #000000; text-align: start;&quot; href=&quot;https://leetcode.com/problems/percentage-of-users-attended-a-contest/&quot;&gt;1633. Percentage of Users Attended a Contest&lt;/a&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/percentage-of-users-attended-a-contest/?envType=study-plan-v2&amp;amp;envId=top-sql-50&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/percentage-of-users-attended-a-contest/?envType=study-plan-v2&amp;amp;envId=top-sql-50&lt;/a&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1744774212569&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT R.CONTEST_ID, ROUND(COUNT(U.USER_ID) / (SELECT COUNT(*) FROM USERS) * 100, 2) AS PERCENTAGE
FROM REGISTER R
INNER JOIN USERS U ON R.USER_ID = U.USER_ID
GROUP BY R.CONTEST_ID
ORDER BY 
    PERCENTAGE DESC, CONTEST_ID ASC&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;a style=&quot;background-color: #f0f0f0; color: #000000; text-align: start;&quot; href=&quot;https://leetcode.com/problems/number-of-unique-subjects-taught-by-each-teacher/&quot;&gt;2356. Number of Unique Subjects Taught by Each Teacher&lt;/a&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/number-of-unique-subjects-taught-by-each-teacher/?envType=study-plan-v2&amp;amp;envId=top-sql-50&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/number-of-unique-subjects-taught-by-each-teacher/?envType=study-plan-v2&amp;amp;envId=top-sql-50&lt;/a&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1744774236171&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/* Write your PL/SQL query statement below */

SELECT T.TEACHER_ID, COUNT(DISTINCT T.SUBJECT_ID) AS CNT
FROM TEACHER T
GROUP BY T.TEACHER_ID&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1 style=&quot;background-color: #ffffff; color: #585f69; text-align: start;&quot;&gt;&lt;span&gt;등수 찾기&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/17616&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/17616&lt;/a&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 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;나의 최대 등수는(낮을수록 좋은 것입니다.) -- &amp;gt; (나보다 확실히 점수가 높은 학생들의 수) + 1&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;나의 최소 등수(가장 최악의 경우) -&amp;gt; 전체학생수 (N) - (나보다 점수가 낮은 학생 수) 입니다.&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;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; 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. graph에 나보다 더 못한 학생들에게 간선으로 연결합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. reverseGraph에 나보다 더 잘한 학생들에게 간선으로 연결합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중요점은, 1-&amp;gt;3-&amp;gt;4 일떄의 연관관계입니다. 1이 3보다 더 잘했다면, 자연스레 1이 4보다 더 잘했다는 의미입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1744797775645&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package Main;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.StringTokenizer;

public class Main {
    static int N, A, B, H, W, K, D, C, S, T, M, L, X;
    static int answer = 0;
    static int[] arr;
    static List&amp;lt;Integer&amp;gt;[] graph;
    static List&amp;lt;Integer&amp;gt;[] reverseGraph;
    static boolean[] visited;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        X = Integer.parseInt(st.nextToken()) - 1;
        
        //그래프 초기화
        graph = new ArrayList[N];
        reverseGraph = new ArrayList[N];
        for(int i=0; i&amp;lt;N; i++) {
        	graph[i] = new ArrayList&amp;lt;&amp;gt;();
        	reverseGraph[i] = new ArrayList&amp;lt;&amp;gt;();
        }
        
        for(int i=0; i&amp;lt;M; i++) {
        	st = new StringTokenizer(br.readLine());
        	A = Integer.parseInt(st.nextToken()) - 1;
        	B = Integer.parseInt(st.nextToken()) - 1;
        	graph[A].add(B);
        	reverseGraph[B].add(A);
        }
        visited = new boolean[N];
        int worseThanX = findWorseDfs(X);
        Arrays.fill(visited, false);
        int betterThanX = findBetterDfs(X);
        
        int minRank =betterThanX + 1;  
        int maxRank = N - worseThanX;
        System.out.println(minRank+&quot; &quot;+maxRank);
    }
    
    static int findWorseDfs(int start) {
    	int ret = 0;
    	for(int i=0; i&amp;lt;graph[start].size(); i++) {
    		int next = graph[start].get(i);
    		if(visited[next] == false) {
    			visited[next] = true;
    			ret += 1 + findWorseDfs(next);
    		}
    	}
    	return ret;
    }
    
    static int findBetterDfs(int start) {
    	int ret = 0;
    	for(int i=0; i&amp;lt;reverseGraph[start].size(); i++) {
    		int next = reverseGraph[start].get(i);
    		if(visited[next] == false) {
    			visited[next] = true;
    			ret += 1 + findBetterDfs(next);
    		}
    	}
    	return ret;
    }
    
    
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제의 핵심은 , 그래프의 구성된 싸이클 없는 간선의 개수를 구하라는 것과 같은데, 문제가 해당 본질을 이해하지 못하도록 하기에 어렵습니다.&lt;/p&gt;
&lt;h1 style=&quot;background-color: #ffffff; color: #585f69; text-align: start;&quot;&gt;&lt;span&gt;회전 초밥&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/15961&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/15961&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전형적인 슬라이딩 윈도우 문제입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1744798560942&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.StringTokenizer;

public class Main {
    static int N, A, B, H, W, K, D, C;
    static int answer = 0;
    static int[] arr;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        D = Integer.parseInt(st.nextToken());
        K = Integer.parseInt(st.nextToken());
        C = Integer.parseInt(st.nextToken());
        
        arr = new int[2*N];

        for(int i=0; i&amp;lt;N; i++) {
        	st = new StringTokenizer(br.readLine());
        	arr[i] = Integer.parseInt(st.nextToken());
        }
        for(int i=N; i&amp;lt;2*N; i++) {
        	arr[i] = arr[i-N];
        }
        
        //처음 K-1개 먼저 먹음
        HashMap&amp;lt;Integer, Integer&amp;gt; hashmap = new HashMap&amp;lt;&amp;gt;();
        for(int i=0; i&amp;lt;K; i++) {
        	hashmap.put(arr[i], hashmap.getOrDefault(arr[i], 0) + 1);
        	if(hashmap.containsKey(C) == false) {
        		answer = Math.max(answer, hashmap.size() + 1); 
        	}else {
        		answer = Math.max(answer, hashmap.size());	
        	}
        }
        
        for(int right=K; right&amp;lt;2*N; right++) {
        	int num = hashmap.get(arr[right - K]);
        	if(num &amp;lt;= 1) {
        		hashmap.remove(arr[right - K]);
        	}else if(num &amp;gt;= 2) {
        		hashmap.put(arr[right - K], num - 1);
        	}
        	
        	hashmap.put(arr[right], hashmap.getOrDefault(arr[right], 0) + 1);
        	
        	if(hashmap.containsKey(C) == false) {
        		answer = Math.max(answer, hashmap.size() + 1); 
        	}else {
        		answer = Math.max(answer, hashmap.size());	
        	}
        	
        }
        System.out.println(answer);
         
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1 style=&quot;background-color: #ffffff; color: #585f69; text-align: start;&quot;&gt;&lt;span&gt;사회적 거리 두기&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/20917&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/20917&lt;/a&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;문제에서 가장 핵심은, 의자 간의 거리를 미리 정해두고 그 거리가 가능한지를 확인하는 것 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특이점은 항상 의자간의 거리를 구할때 맨 앞 의자에서부터 시작해도 됩니다. ( 이 부분이 헷갈릴 수 있으나, 반드시 맨 앞에서부터 앉아야 그것이 최선 값입니다. )&lt;/p&gt;
&lt;pre id=&quot;code_1744798663385&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.StringTokenizer;

public class Main {
    static int N, A, B, H, W, K, D, C, S, T;
    static int answer = 0;
    static int[] arr;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        
        T = Integer.parseInt(st.nextToken());
        
        while(T -- &amp;gt; 0) {
        	st = new StringTokenizer(br.readLine());
        	N = Integer.parseInt(st.nextToken());
        	S = Integer.parseInt(st.nextToken());
        	
        	arr = new int[N];
        	st = new StringTokenizer(br.readLine());
        	for(int i=0; i&amp;lt;N; i++) {
        		arr[i] = Integer.parseInt(st.nextToken());
        	}
        	Arrays.sort(arr);
        	System.out.println(optimize(0, N));
        }
    }
    
    static int optimize(int s, int e) {
    	int left = -1;
    	int right = 1000000001;
    	
    	while(left + 1 &amp;lt; right) {
    		int mid = (left + right) / 2;
    		if(decision(mid) == true) {
    			left = mid;
    		}else {
    			right = mid;
    		}
    	}
    	return right - 1;
    }
    
    static boolean decision(int dist) {
    	int seatCnt = 1;
    	int seatPos = arr[0];
    	for(int i=1; i&amp;lt;N; i++) {
    		if(arr[i] - seatPos &amp;gt;= dist) {
    			seatCnt += 1;
    			seatPos = arr[i];
    		}
    	}
    	return seatCnt &amp;gt;= S;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1 style=&quot;background-color: #ffffff; color: #585f69; text-align: start;&quot;&gt;&lt;span&gt;휴게소 세우기&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/1477&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/1477&lt;/a&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;이 문제 같은 경우 휴게소 간 길이를 매개변수로 두고, 해당 길이로 휴게소를 배치했을때 딱 M개가 되는지가 쟁점입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만, decision 결정함수를 구현하면서, arr[i+1] - arr[i] - 1 에서 -1 을 하는거라든지와 같이, 혹은 휴게소의 시작점과 끝점은 냅두는 것. 그리고 이분탐색에서 제가 구현한 방식은 (lo, hi)이기에 [lo + 1, hi - 1]의 범위를 가진다는 점들에 어려움을 겪어서 구현하지 못했습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1744798705286&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.StringTokenizer;

public class Main {
    static int N, A, B, H, W, K, D, C, S, T, M, L;
    static int answer = 0;
    static int[] arr;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        
        
    	N = Integer.parseInt(st.nextToken());
    	M = Integer.parseInt(st.nextToken());
    	L = Integer.parseInt(st.nextToken());
    	arr = new int[N + 2];
    	arr[0] = 0;
    	st = new StringTokenizer(br.readLine());
    	for(int i=1; i&amp;lt;=N; i++) {
    		arr[i] = Integer.parseInt(st.nextToken());
    	}
    	arr[N+1] = L;
    	
    	Arrays.sort(arr);
    	System.out.println(optimize());
    }
    
    static int optimize() {
    	int left = 0;
    	int right = L;
    	//휴게소 간 길이가 매개변수가 됩니다.
    	//해당 매개변수로 휴게소를 지을 수 있다면, 더 줄여봅니다.
    	while(left + 1 &amp;lt; right) {
    		int mid = (left + right) / 2;
    		if(decision(mid) == true) {
    			left = mid;
    		}else {
    			right = mid;
    		}
    	}
    	return right;
    }
    
    static boolean decision(int dist) {
    	int cnt = 0;
    	for(int i=0; i&amp;lt;N+1; i++) {
    		cnt += (arr[i+1] - arr[i] - 1) / dist;
    	}
    	return cnt &amp;gt; M;
    }
    
    
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>알고리즘/랜덤디펜스</category>
      <author>passionfruit200</author>
      <guid isPermaLink="true">https://passionfruit200.tistory.com/1677</guid>
      <comments>https://passionfruit200.tistory.com/1677#entry1677comment</comments>
      <pubDate>Wed, 16 Apr 2025 12:31:21 +0900</pubDate>
    </item>
    <item>
      <title>[백준][랜덤디펜스] 골랜디 Virtual #3</title>
      <link>https://passionfruit200.tistory.com/1676</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;골랜디&amp;nbsp;Virtual&amp;nbsp;#3&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 : 0/4&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SQL : 1/2&lt;/p&gt;
&lt;h1 style=&quot;background-color: #ffffff; color: #585f69; text-align: start;&quot;&gt;&lt;span&gt;연속 XOR&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/25306&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/25306&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 문제를 읽고 그대로 구현했다가 시간초과가 발생했습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1744709046956&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {
	static int N, M, S, K;
	static long answer = 0;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        		
        long A = Long.parseLong(st.nextToken());
        long B = Long.parseLong(st.nextToken());
        
        answer = A;
        for(long i=A + 1; i&amp;lt;=B; i++) {
        	answer ^= i;
        }
        System.out.println(answer);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;문제는 10^18 이기에 당연히 시간초과입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;업솔빙하기 위해 좀 찾아보니, XOR 사용시&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;0 1 2 3, 4 5 6 7, 8 9 10 11, 12 13 14 15 ... 이렇게 4개씩 숫자가 짤리면서 해당 구간은 모두 XOR 연산을 할시 0이 나온다고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이유는 00 01 10 11 을 예시로 보면, (0, 1, 2, 3 입니다.)&amp;nbsp; 결국 XOR 연산이 되면서 00 이 되는 걸 볼 수 있습니다. 즉, 해당 구간의 XOR 연산값은 항상 0 이기에 의미가 없다고하는데, 온전히 이해하지는 못했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1 style=&quot;background-color: #ffffff; color: #585f69; text-align: start;&quot;&gt;&lt;span&gt;사전 순 최대 공통 부분 수열&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/30805&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/30805&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최대 공통 부분 수열은 구할 수 있었으나, &quot;사전 순으로 가장 나중&quot;인것을 구하는 방법을 모르겠어서 실패했습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1744709371776&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Stack;
import java.util.StringTokenizer;

public class Main {
	static int N, M, S, K;
	static int[][] dp;
	static int[] arr, brr;
	static long answer = 0;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        N = Integer.parseInt(st.nextToken());
        arr = new int[N];
        st = new StringTokenizer(br.readLine());
        for(int i=0; i&amp;lt;N; i++) {
        	arr[i] = Integer.parseInt(st.nextToken());
        }
        st = new StringTokenizer(br.readLine());
        M = Integer.parseInt(st.nextToken());
        brr = new int[M];
        st = new StringTokenizer(br.readLine());
        for(int i=0; i&amp;lt;M; i++) {
        	brr[i] = Integer.parseInt(st.nextToken());
        }
        
        dp = new int[N + 1][M + 1];
        
        for(int col = 0; col &amp;lt; M+1; col++) {
        	dp[0][col] = 0;
        }
        
        for(int row = 0; row &amp;lt; N+1; row++) {
        	dp[row][0] = 0;
        }
        
        for(int row=1; row &amp;lt; N+1; row++) {
        	for(int col = 1; col &amp;lt; M+1; col++) {
        		if(arr[row - 1] == brr[col - 1]) {
        			dp[row][col] = dp[row-1][col-1] + 1;
        		}
        		else {
        			dp[row][col] = Math.max(dp[row-1][col-1], Math.max(dp[row-1][col], dp[row][col-1]));
        		}
        	}
        }
        
//        for(int r=0; r&amp;lt;N+1; r++) {
//        	for(int c = 0; c&amp;lt;M+1; c++) {
//        		System.out.print(dp[r][c]+&quot; &quot;);
//        	}
//        	System.out.println();
//        }
//        
        
        int r = N;
        int c = M;
        ArrayList&amp;lt;Integer&amp;gt; ret = new ArrayList&amp;lt;&amp;gt;();
        Stack&amp;lt;Integer&amp;gt; stack = new Stack&amp;lt;&amp;gt;();
        while(r &amp;gt; 0 &amp;amp;&amp;amp; c &amp;gt; 0) {
        	if(arr[r - 1] == brr[c - 1]) {
        		stack.add(arr[r - 1]);
        		r -= 1;
        		c -= 1;
        	}else {
        		if(dp[r-1][c] &amp;gt; dp[r][c-1]) {
        			r -= 1;
        			c -= 0;
        		}else {
        			r -= 0;
        			c -= 1;
        		}
        	}
        }
//        System.out.println();
        
        int maxNum = -1;
        while(!stack.isEmpty()) {
        	int num = stack.pop();
        	maxNum = Math.max(maxNum, num);
        	ret.add(num);
        }
        //1 7 3의 모든 부분집합 구하기.
        //가장 큰 수 구하고, 그 숫자를 기반으로 뒤에 있는것 모두 출력.
        ArrayList&amp;lt;Integer&amp;gt; longestPerm = new ArrayList&amp;lt;&amp;gt;();
        boolean isMet = false;
        for(int i=0; i&amp;lt;ret.size(); i++) {
        	if(ret.get(i) == maxNum) {
        		isMet = true;
        	}
        	if(isMet == true) {
        		longestPerm.add(ret.get(i));
        	}
        }
        System.out.println(longestPerm.size());
        for(int v : longestPerm) {
        	System.out.print(v+&quot; &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;다음에 다시 풀어봐야할 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1 style=&quot;background-color: #ffffff; color: #585f69; text-align: start;&quot;&gt;&lt;span&gt;엔토피아의 기억강화&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/23280&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/23280&lt;/a&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_1744712119209&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package Main;
import java.io.*;
import java.util.*;

public class Main {
    static int N, A, B;
    static int[] arr;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        N = Integer.parseInt(st.nextToken());
        A = Integer.parseInt(st.nextToken());
        B = Integer.parseInt(st.nextToken());

        arr = new int[N];
        st = new StringTokenizer(br.readLine());
        for(int i=0; i&amp;lt;N; i++) {
        	arr[i] = Integer.parseInt(st.nextToken());
        }
        
        int[][][] dp = new int[N+1][13][13];
        for(int i=0; i&amp;lt;N+1; i++) {
        	for(int j=0; j&amp;lt;13; j++) {
        		Arrays.fill(dp[i][j], Integer.MAX_VALUE/2);
        	}
        }
        dp[0][1][3] = 0;
        
        for(int i=0; i&amp;lt;N; i++) {
        	int targetNumber = arr[i];
        	
        	for(int r=1; r&amp;lt;=12; r++) {
        		for(int c=1; c&amp;lt;=12; c++) {
        			//왼손으로 누를때,
        			int dist = getEnergy(r, targetNumber);
        			int nextLeft = targetNumber;
        			int nextRight = c;
        			dp[i+1][nextLeft][nextRight] = Math.min(dp[i+1][nextLeft][nextRight], dp[i][r][c] + dist + A);
        			
        			//오른손 누를때
        			dist = getEnergy(c, targetNumber);
        			nextLeft = r;
        			nextRight = targetNumber;
        			dp[i+1][nextLeft][nextRight] = Math.min(dp[i+1][nextLeft][nextRight], dp[i][r][c] + dist + B);
        		}
        	}
        }
        
        int answer = Integer.MAX_VALUE;
        for(int r=1; r&amp;lt;=12; r++) {
        	for(int c=1; c&amp;lt;=12; c++) {
        		answer = Math.min(answer,dp[N][r][c]);
        	}
        }
        System.out.println(answer);
    }
    
    static int getEnergy(int from, int to) {
    	int r1 = (from-1) / 3; int c1 = (from-1) % 3;
    	int r2 = (to-1) / 3; int c2 = (to - 1) % 3;
    	return Math.abs(r1 - r2) + Math.abs(c1 - c2);
    }

}&lt;/code&gt;&lt;/pre&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_1746463868125&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package Main;

import java.io.*;
import java.util.*;

public class Main {
    static int N, A, B;
    static int[] arr;
    static int[][][] dp;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        N = Integer.parseInt(st.nextToken());
        A = Integer.parseInt(st.nextToken());
        B = Integer.parseInt(st.nextToken());

        arr = new int[N];
        st = new StringTokenizer(br.readLine());
        for (int i = 0; i &amp;lt; N; i++) {
            arr[i] = Integer.parseInt(st.nextToken());
        }

        // dp[pos][left][right] = 최소 비용
        dp = new int[N][13][13];
        for (int i = 0; i &amp;lt; N; i++) {
            for (int l = 1; l &amp;lt;= 12; l++) {
                Arrays.fill(dp[i][l], -1); // 아직 계산되지 않은 상태
            }
        }

        // 시작 위치: 왼손 1, 오른손 3
        int answer = dfs(0, 1, 3);
        System.out.println(answer);
    }

    static int dfs(int idx, int left, int right) {
        if (idx == N) return 0;

        if (dp[idx][left][right] != -1) return dp[idx][left][right];

        int target = arr[idx];

        // 왼손으로 누를 경우
        int costLeft = getEnergy(left, target) + A + dfs(idx + 1, target, right);
        // 오른손으로 누를 경우
        int costRight = getEnergy(right, target) + B + dfs(idx + 1, left, target);

        return dp[idx][left][right] = Math.min(costLeft, costRight);
    }

    static int getEnergy(int from, int to) {
        int r1 = (from - 1) / 3, c1 = (from - 1) % 3;
        int r2 = (to - 1) / 3, c2 = (to - 1) % 3;
        return Math.abs(r1 - r2) + Math.abs(c1 - c2);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1 style=&quot;background-color: #ffffff; color: #585f69; text-align: start;&quot;&gt;&lt;span&gt;조명 배치&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/26124&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/26124&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계속해서 시간초과가 발생해서 포기했습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1744720964406&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package Main;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.StringTokenizer;

public class Main {
    static int N, A, B, H, W;
    static int[][] map;
    static int[][] newMap;
    static Queue&amp;lt;int[]&amp;gt; q = new LinkedList&amp;lt;&amp;gt;();
    static int answer = 0;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        
        H = Integer.parseInt(st.nextToken());
        W = Integer.parseInt(st.nextToken());
        PriorityQueue&amp;lt;int[]&amp;gt; pq = new PriorityQueue&amp;lt;int[]&amp;gt;(new Comparator&amp;lt;int[]&amp;gt;() {
        	@Override
        	public int compare(int[] a, int[] b) {
        		return b[2] - a[2];
        	}
        });
        
        map = new int[H][W];
        newMap = new int[H][W];
        for(int i=0; i&amp;lt;H; i++) {
        	Arrays.fill(newMap[i], Integer.MIN_VALUE);
        }
        
        for(int i=0; i&amp;lt;H; i++) {
        	st = new StringTokenizer(br.readLine());
        	for(int j=0; j&amp;lt;W; j++) {
        		int num = Integer.parseInt(st.nextToken());
        		map[i][j] = num;
        		if(map[i][j] &amp;gt; 0 &amp;amp;&amp;amp; map[i][j] != -1)
        			pq.add(new int[] {i, j, map[i][j]});
        		if(map[i][j] == -1 || map[i][j] == 0) {
        			newMap[i][j] = map[i][j];
        		}
        	}
        }
        
        // 먼저 인접한 셀의 밝기 차이가 1보다 큰지 확인
        for(int i = 0; i &amp;lt; H; i++) {
            for(int j = 0; j &amp;lt; W; j++) {
                if(map[i][j] &amp;lt; 0) continue; // 조명이 없거나 벽인 경우 패스
                int val = map[i][j];
                for(int[] d : new int[][]{{-1, 0}, {1, 0}, {0, -1}, {0, 1}}) {
                    int nr = i + d[0];
                    int nc = j + d[1];
                    
                    if(nr &amp;lt; 0 || nr &amp;gt;= H || nc &amp;lt; 0 || nc &amp;gt;= W) continue;
                    if(map[nr][nc] == -1) continue; // 벽인 경우 패스
                    
                    // 인접한 셀의 밝기 차이가 1보다 크면 불가능
                    if(Math.abs(val - map[nr][nc]) &amp;gt; 1) {
                        System.out.println(-1);
                        return;
                    }
                }
            }
        }
        
        answer = 0;
        while(!pq.isEmpty()) {
        	int[] here = pq.poll();
        	int r = here[0];
        	int c = here[1];
        	int val = here[2];
        	if(val == -1) continue;
        	if(newMap[r][c] == val) continue;
        	if(newMap[r][c] &amp;gt; map[r][c]) {
        		System.out.println(-1);return;
        	}
    		newMap[r][c] = val;
    		BFSLight(r, c, val);
    		answer += 1;
    	}
        System.out.println(answer);

    }	
    static void BFSLight(int sr, int sc, int sval) {
    	boolean[][] visited = new boolean[H][W];
    	visited[sr][sc] = true;
		//해당 위치에서 사방으로 퍼져나갑니다.
		Queue&amp;lt;int[]&amp;gt; q = new LinkedList&amp;lt;&amp;gt;();
		for(int[] dir : new int[][]{ {-1, 0},{1, 0}, {0, -1}, {0,1}}){
			int nr = sr + dir[0];
			int nc = sc + dir[1];
			int nval = sval - 1;
			if(nval &amp;lt; 0) continue;
			if(nr  &amp;lt; 0 || nr  &amp;gt;= H || nc &amp;lt; 0 || nc &amp;gt;= W) continue;
			if(newMap[nr][nc] == -1) continue;
			if(visited[nr][nc] == true) continue;
			if(newMap[nr][nc] &amp;gt;= map[nr][nc]) continue;
			visited[nr][nc] = true;
			q.offer(new int[]{nr, nc, nval});
		}
		
		while(!q.isEmpty()) {
			int[] here = q.poll();
			int r = here[0];
			int c = here[1];
			int val = here[2];
			if(newMap[r][c] &amp;gt; val) continue;
			newMap[r][c] = Math.max(newMap[r][c], val);
			
			for(int[] dir : new int[][]{ {-1, 0},{1, 0}, {0, -1}, {0,1}}){
				int nr = r + dir[0];
				int nc = c + dir[1];
				int nval = val - 1;
				if(nval &amp;lt; 0) continue;
				if(nr  &amp;lt; 0 || nr &amp;gt;= H || nc &amp;lt; 0 || nc &amp;gt;= W) continue;
				if(visited[nr][nc] == true) continue;
				if(newMap[nr][nc] &amp;gt;= map[nr][nc]) continue;
				visited[nr][nc] = true;
				q.offer(new int[]{nr, nc, nval});
			}
			
		}    	
    }
}&lt;/code&gt;&lt;/pre&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;a style=&quot;background-color: #f0f0f0; color: #000000; text-align: start;&quot; href=&quot;https://leetcode.com/problems/average-selling-price/&quot;&gt;1251. Average Selling Price&lt;/a&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/average-selling-price/description/?envType=study-plan-v2&amp;amp;envId=top-sql-50&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/average-selling-price/description/?envType=study-plan-v2&amp;amp;envId=top-sql-50&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LEFT OUTER JOIN을 사용했을 때 테이블을 상상할 수 있어야만 풀 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상상이 된다면, GROUP BY P.PROUDCT_ID로 어떤 일이 일어날지 예상이 가겠지요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가로, 처음에는 LEFT OUTER JOIN 시 레코드가 없는경우 NULL이 나와서 올바르게 처리가 안되었는데, CASE WHEN으로 만약 JOIN 했을때 값이 없다면 0 으로 나오도록 처리합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1744722228550&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT P.PRODUCT_ID, 
    CASE 
        WHEN COUNT(U.PRODUCT_ID) = 0 THEN 0
        ELSE ROUND(SUM(P.PRICE * U.UNITS) / SUM(U.UNITS), 2) 
    END AS AVERAGE_PRICE
FROM PRICES P
LEFT OUTER JOIN UNITSSOLD U ON P.PRODUCT_ID = U.PRODUCT_ID AND U.PURCHASE_DATE BETWEEN P.START_DATE AND END_DATE
GROUP BY P.PRODUCT_ID&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;a style=&quot;background-color: #f0f0f0; color: #000000; text-align: start;&quot; href=&quot;https://leetcode.com/problems/project-employees-i/&quot;&gt;1075. Project Employees I&lt;/a&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/project-employees-i/description/?envType=study-plan-v2&amp;amp;envId=top-sql-50&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/project-employees-i/description/?envType=study-plan-v2&amp;amp;envId=top-sql-50&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제의 경우 또한 LEFT OUTER JOIN을 통해 해결할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;항상 LEFT OUTER JOIN 실행 후의 테이블 모습을 상상할 수 있어야 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1744722249128&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT P.PROJECT_ID, ROUND(SUM(E.EXPERIENCE_YEARS) / COUNT(E.EMPLOYEE_ID), 2) AS AVERAGE_YEARS
FROM PROJECT P
LEFT OUTER JOIN EMPLOYEE E ON P.EMPLOYEE_ID = E.EMPLOYEE_ID
GROUP BY P.PROJECT_ID&lt;/code&gt;&lt;/pre&gt;</description>
      <category>알고리즘/랜덤디펜스</category>
      <author>passionfruit200</author>
      <guid isPermaLink="true">https://passionfruit200.tistory.com/1676</guid>
      <comments>https://passionfruit200.tistory.com/1676#entry1676comment</comments>
      <pubDate>Tue, 15 Apr 2025 22:07:49 +0900</pubDate>
    </item>
    <item>
      <title>[백준][랜덤디펜스] 골랜디 Virtual #2</title>
      <link>https://passionfruit200.tistory.com/1674</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;골랜디&amp;nbsp;Virtual&amp;nbsp;#2&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘은 2문제 Solve, 2문제 Fail. 2/4&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SQL은 1문제 Solve, 2문제 Fail&amp;nbsp; 했습니다. 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;한 문제씩 리뷰 남깁니다.&lt;/p&gt;
&lt;h1 style=&quot;background-color: #ffffff; color: #585f69; text-align: start;&quot;&gt;&lt;span&gt;준영이의 사랑&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/30014&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/30014&lt;/a&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;처음에는 원형이라는 말이 존재해서, 기존 배열에 똑같이 기존 배열을 붙이고서, 슬라이딩 윈도우로 무엇인가 하는것인가?라는 생각이 들었지만, * 연산이 있어서 슬라이딩 윈도우 적용이 어려웠고, 애초에 문제가 잘 이해가지 않았습니다. 개인적으로 문제가 이해가 안가면, 그만큼 어려운것같습니다.&lt;/p&gt;
&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. 홀수인덱스면 앞쪽에, 짝수인덱스면 뒤쪽에 삽입합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1 2 3 4 5 라면,&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 2&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3 1 2&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3 1 2 4&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5 3 1 2 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;풀이를 봐도 이해가 가지않아, 넘어가겠습니다.&lt;/p&gt;
&lt;h1 style=&quot;background-color: #ffffff; color: #585f69; text-align: start;&quot;&gt;&lt;span&gt;빛의 왕과 거울의 미로 1&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/10725&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/10725&lt;/a&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;문제에서 헤맸던 부분은, 모든 판을 이미 만들고서 레이저를 쏴야 합니다.&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;pre id=&quot;code_1744626637789&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {
	static int N, M, S, K, X, Y;
	static int answer = 0;
	static char[][] map;
	static int sX = 0, sY = 0, sDir = 0;
	static int MOD = 10007;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        X = Integer.parseInt(st.nextToken());
        Y = Integer.parseInt(st.nextToken());
        map = new char[N+2][M+2];
        
        int num = 1;
        for(int col=1; col&amp;lt;M+1; col++) {
        	map[0][col] = (char) (num++);
        }
        for(int row=1; row &amp;lt;=N; row++) {
        	map[row][0] = (char)(num++);
        }
        for(int row=1; row &amp;lt;=N; row++) {
        	map[row][M+1] = (char)(num++);
        }
        for(int col=1; col&amp;lt;M+1; col++) {
        	map[N+1][col] = (char) (num++);
        }
        
        for(int i=1; i&amp;lt;=N; i++) {
        	st = new StringTokenizer(br.readLine());
        	String str = st.nextToken();
        	for(int j=1; j&amp;lt;=M; j++) {
        		map[i][j] =str.charAt(j - 1); 
        	}
        }
        
        for(int i=0; i&amp;lt;N+2; i++) {
        	for(int j=0; j&amp;lt;M+2; j++) {
        		if( (int) map[i][j] == X) {
        			//위에서 레이저
        			if(i == 0) {
        				sX = i + 1;
        				sY = j;
        				sDir = 0;
        			}
        			//아래에서 레이저
        			else if(i == N+1) {
        				sX = i - 1;
        				sY = j;
        				sDir = 1;
        			}
        			//왼쪽에서 레이저
        			else if(j == 0) {
        				sX = i;
        				sY = j + 1;
        				sDir = 2;
        			}
        			//오른쪽에서 레이저
        			else if(j == M+1) {
        				sX = i;
        				sY = j - 1;
        				sDir = 3;
        			}
        		}
        	}
        }
        makeGraph(1, 1);
        System.out.println(answer % MOD);
    }
    
    static void makeGraph(int hereX, int hereY) {
    	if(hereX == N &amp;amp;&amp;amp; hereY == M+1) {
    		answer += DFS(sX, sY, sDir) % MOD;
    		return ;
    	}
    	
    	if(hereY &amp;gt; M) {
    		hereX += 1;
    		hereY = 1;
    	}
    	
    	if(map[hereX][hereY] =='?') {
    		map[hereX][hereY] = '\\';
    		makeGraph(hereX, hereY + 1);
			map[hereX][hereY] = '/';
			makeGraph(hereX, hereY + 1);
    		map[hereX][hereY] = '.';
    		makeGraph(hereX, hereY + 1);
    		map[hereX][hereY] = '?';
    	}else {
    		makeGraph(hereX, hereY + 1);
    	}
    	
    }
    
    
    static int DFS(int hereX, int hereY, int dir) {
    	if( (int) map[hereX][hereY] == Y ) {
    		return 1;
    	}
    	if( hereX &amp;lt;= 0 || hereX &amp;gt; N || hereY &amp;lt;= 0 || hereY &amp;gt; M) return 0;
    	
    	
    	int ret = 0;
    	if(map[hereX][hereY] == '/') {
    		//위에서 온다면, 왼쪽으로 간다.
        	if(dir == 0) {
        		ret += DFS(hereX, hereY - 1, 3) % MOD;
        	}
        	//아래에서 온다면 오른쪽으로 간다.
        	else if(dir == 1) {
        		ret += DFS(hereX, hereY + 1, 2) % MOD;
        	}
        	//왼쪽에서 온다면 위로간다.
        	else if(dir == 2) {
        		ret += DFS(hereX - 1, hereY, 1) % MOD;
        	}
        	//오른쪽에서 온다면 아래로 간다.
        	else if(dir == 3) {
        		ret += DFS(hereX + 1, hereY, 0) % MOD;
        	}
    	}
    	
    	if(map[hereX][hereY] == '\\'){
    		//위에서 온다면, 오른쪽으로 간다.
        	if(dir == 0) {
        		ret += DFS(hereX, hereY + 1, 2) % MOD;
        	}
        	//아래에서 온다면 왼쪽으로 간다.
        	else if(dir == 1) {
        		ret += DFS(hereX, hereY - 1, 3) % MOD;
        	}
        	//왼쪽에서 온다면, 아래로 간다.
        	else if(dir == 2) {
        		ret += DFS(hereX + 1, hereY, 0) % MOD;
        	}
        	//오른쪽에서 온다면, 위로 간다.
        	else if(dir == 3) {
        		ret += DFS(hereX - 1, hereY, 1)% MOD;
        	}    			
    	}
    	
    	if(map[hereX][hereY] == '.') {
    		//위에서 온다면, 아래로 간다.
        	if(dir == 0) {
        		ret += DFS(hereX + 1, hereY, 0) % MOD;
        	}
        	//아래에서 온다면 위로 간다.
        	else if(dir == 1) {
        		ret += DFS(hereX - 1, hereY, 1) % MOD;
        	}
        	//왼쪽에서 온다면, 오른쪽으로 간다.
        	else if(dir == 2) {
        		ret += DFS(hereX, hereY + 1, 2) % MOD;
        	}
        	//오른쪽에서 온다면, 왼쪽으로 간다.
        	else if(dir == 3) {
        		ret += DFS(hereX, hereY - 1, 3) % MOD;
        	}    			    		
    	}
    	
    	return ret % MOD;
    }
    
    
}&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;h1 style=&quot;background-color: #ffffff; color: #585f69; text-align: start;&quot;&gt;&lt;span&gt;순회강연&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/2109&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/2109&lt;/a&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;이전에 비슷한 문제를 풀어보았습니다. (어떤 문제인지는 기억이 안남)&lt;/p&gt;
&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;여기서 PQ가 작업 큐가 되겠습니다. 그리고 pq의 사이즈가 하루에 1개의 강연만 진행할 수 있기에, 인덱스 자체가 될 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1744626695684&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.StringTokenizer;

public class Main {
	static int N, M, S, K;
	static int answer = 0;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        
        N = Integer.parseInt(st.nextToken());
        Integer[][] arr = new Integer[N][2];
        
        for(int i=0; i&amp;lt;N; i++) {
        	st = new StringTokenizer(br.readLine());
        	arr[i][0] = Integer.parseInt(st.nextToken());
        	arr[i][1] = Integer.parseInt(st.nextToken());
        }
        
        Arrays.sort(arr, new Comparator&amp;lt;Integer[]&amp;gt;() {
        	@Override
        	public int compare(Integer[] a, Integer[] b) {
        		if(a[1] == b[1]) {
        			return b[0] - a[0];
        		}
        		return a[1] - b[1];
        	}
        });
        
        PriorityQueue&amp;lt;Integer&amp;gt; pq = new PriorityQueue&amp;lt;&amp;gt;();
        
        for(int i=0; i&amp;lt;N; i++) {
        	int deadLine = arr[i][1];
        	int pay = arr[i][0];
        	if(pq.size() &amp;lt; deadLine) {
        		pq.offer(pay);
        	}else if( pq.peek() &amp;lt; pay ){
        		pq.poll();
        		pq.offer(pay);
        	}
        }
        
        while(!pq.isEmpty()) {
//        	System.out.println(pq.peek());
        	answer += pq.poll();
        }
        
        System.out.println(answer);
    }
}&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;h1 style=&quot;background-color: #ffffff; color: #585f69; text-align: start;&quot;&gt;&lt;span&gt;나는 건포도가 싫어요&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/32986&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/32986&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정말 감이 안와서, 생각해보니 Size가 2일때 건포도의 위치를 바로 확인할 수 있다고 생각했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 X, Y, Z에서 사실 X, Y 만 고려해도 되는것 아닌가? 하는 생각이 들어서&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;pre id=&quot;code_1744626816329&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Main {
	static int N, M, S, K;
	static int answer = 0;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        
        int A = Integer.parseInt(st.nextToken());
        int B = Integer.parseInt(st.nextToken()); 
        int C = Integer.parseInt(st.nextToken());
        
        System.out.println( ((A/2)-1) * ((B/2)-1));
    }
}&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;h2 data-ke-size=&quot;size26&quot;&gt;1193.&amp;nbsp;Monthly&amp;nbsp;Transactions&amp;nbsp;I&lt;/h2&gt;
&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://leetcode.com/problems/monthly-transactions-i/description/?envType=study-plan-v2&amp;amp;envId=top-sql-50&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/monthly-transactions-i/description/?envType=study-plan-v2&amp;amp;envId=top-sql-50&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SQL 연습하며, 가장 어려운 부분은 Oracle에서는 to_char함수를 사용하고, Mysql에서는 date_format 을 활용하고 %로 데이터 형식(Format) 맞춰야한다는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 부분 문법이 기억안났다는 점 뺴고는 크게 어렵지 않습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1744626843036&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT TO_CHAR(TRANS_DATE, 'YYYY-MM') as month, COUNTRY as country, COUNT(*) as trans_count,
    sum(
        CASE
            WHEN STATE = 'approved' then 1
            else 0
        END
    ) as &quot;approved_count&quot;,
    sum(amount) as trans_total_amount,
    sum(
        CASE
            WHEN STATE = 'approved' then amount
            else 0
        END
    ) as &quot;approved_total_amount&quot;
FROM TRANSACTIONS
GROUP BY TO_CHAR(TRANS_DATE, 'YYYY-MM'), COUNTRY&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;a style=&quot;background-color: #f0f0f0; color: #000000; text-align: start;&quot; href=&quot;https://leetcode.com/problems/immediate-food-delivery-ii/&quot;&gt;1174. Immediate Food Delivery II&lt;/a&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/immediate-food-delivery-ii/description/?envType=study-plan-v2&amp;amp;envId=top-sql-50&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/immediate-food-delivery-ii/description/?envType=study-plan-v2&amp;amp;envId=top-sql-50&lt;/a&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;윈도우함수를 통해서 가장 첫번쨰 주문값을 구한뒤, 해당값을 Inline View에 넣고 처리하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1744633674885&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT ROUND(100.0 * SUM(
    CASE 
        WHEN ORDER_DATE = CUSTOMER_PREF_DELIVERY_DATE THEN 1
        ELSE 0
    END
) / COUNT(*), 2) AS IMMEDIATE_PERCENTAGE
FROM (SELECT CUSTOMER_ID, ORDER_DATE, CUSTOMER_PREF_DELIVERY_DATE, ROW_NUMBER() OVER (PARTITION BY CUSTOMER_ID ORDER BY ORDER_DATE) AS RN
FROM DELIVERY)
WHERE RN = 1;&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;흠.. 아직 윈도우함수 문법이 익숙하지 않은 것 같습니다. ROW_NUMBER() OVER (PARTITION BY CUSTOMER_ID ORDER BY ORDER_DATE) 의미는 CUSTOMER_ID로 파티셔닝해서 해당 값 내에서 ORDER_DATE로 정렬해서 보여주라는 의미입니다.&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;추가로 위에서는 직접 SUM() / COUNT(*)로 하고 있는데, AVG로 해도됩니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;a style=&quot;background-color: #f0f0f0; color: #000000; text-align: start;&quot; href=&quot;https://leetcode.com/problems/game-play-analysis-iv/&quot;&gt;550. Game Play Analysis IV&lt;/a&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/game-play-analysis-iv/description/?envType=study-plan-v2&amp;amp;envId=top-sql-50&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/game-play-analysis-iv/description/?envType=study-plan-v2&amp;amp;envId=top-sql-50&lt;/a&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;이 문제의 경우, 가장 먼저 로그인한 정보를 가져온뒤 그 값과 일종의 INNER JOIN , 여기서는 IN 절로 비교하면서 값을 가져옵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 문제점은, &quot; &lt;span style=&quot;background-color: #000000; color: #f63636; text-align: start;&quot;&gt;ORA-00937: not a single-group group function&lt;/span&gt; &quot; 에러입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SELECT절에 존재하는 COUNT(DISTINCT A3.PLAYER_ID)가 GROUP BY 에서 GROUP BY 문이 아닌것이 SELECT절에 발생하여 나오는 문제입니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1744635726782&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT ROUND(
    COUNT(A1.player_id)
    / (SELECT COUNT(DISTINCT A3.player_id) FROM Activity A3)
  , 2) AS fraction
FROM ACTIVITY A1
WHERE (PLAYER_ID, TO_CHAR(A1.EVENT_DATE - 1, 'YYYY-MM-DD')) IN (
SELECT PLAYER_ID, TO_CHAR(MIN(EVENT_DATE), 'YYYY-MM-DD')
FROM ACTIVITY A2
GROUP BY PLAYER_ID
);&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;대신에 아래와 같이 ACTIVITY에서 각 플레이어를 LEFT OUTER JOIN 으로 모든 경우를 다 가져오고, WHERE 절로 첫째 날 기준으로만 가져오는 방식이 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1744636026952&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT ROUND(COUNT(A2.PLAYER_ID) / COUNT(A1.PLAYER_ID), 2) AS FRACTION
FROM ACTIVITY A1 LEFT OUTER JOIN ACTIVITY A2 ON A2.PLAYER_ID = A1.PLAYER_ID AND A2.EVENT_DATE = A1.EVENT_DATE + 1
WHERE ( A1.PLAYER_ID, A1.EVENT_DATE) IN (sELECT PLAYER_ID, MIN(EVENT_DATE) FROM ACTIVITY GROUP BY PLAYER_ID)&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>passionfruit200</author>
      <guid isPermaLink="true">https://passionfruit200.tistory.com/1674</guid>
      <comments>https://passionfruit200.tistory.com/1674#entry1674comment</comments>
      <pubDate>Sun, 13 Apr 2025 08:30:38 +0900</pubDate>
    </item>
    <item>
      <title>[백준][랜덤디펜스] 골랜디 Virtual #2</title>
      <link>https://passionfruit200.tistory.com/1673</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;골랜디&amp;nbsp;20250412&amp;nbsp;#1&amp;nbsp;Virtual&amp;nbsp;후기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;골랜디를 진행해보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘 느낀점은, 아직 g3 이상의 DP, Greedy 문제를 다루기에는 역부족하다는 것 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래도 g5, g4 수준의 단순 구현이나 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;SQL의 경우, easy 난이도는 말그대로 단순 문법이고, medium은 2문제 중 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;업솔빙한 문제로는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 : 7570 줄세우기, 1781 컵라면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SQL : 1934 Confirmation Rate를 Upsolving했습니다.&lt;/p&gt;
&lt;h1 style=&quot;background-color: #ffffff; color: #585f69; text-align: start;&quot;&gt;&lt;span&gt;줄 세우기&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/7570&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/7570&lt;/a&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;완전탐색의 경우 어린이 수가(10*6)이기에 완탐 시 지수승으로 수렴하여 시간초과가 발생합니다.&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;&lt;b&gt;업솔빙&lt;/b&gt;하며, 숫자를 맨 뒤나 맨 앞으로만 이동시킬 수 있기에 LIS인데, + 1 간격인 LIS를 구하는 것임을 이해했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에 LIS 코드를 작성하였습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1744431070493&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Main {
	static int N;
	static int answer = 0;
	static int[] arr;
	static int[] cache = new int[1000001];
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        
        st = new StringTokenizer(br.readLine());
        arr = new int[N];
        for(int i=0; i&amp;lt;N; i++) {
        	arr[i] = Integer.parseInt(st.nextToken());
        }
        Arrays.fill(cache, -1);
        
        for(int i=0; i&amp;lt;N; i++) {
        	answer = Math.max(answer, solve(i));
        }
        
        System.out.println(N - answer);
    }
    
    static int solve(int idx) {
    	if(idx == N-1) {
    		return 1;
    	}
    	if(cache[idx] != -1) return cache[idx];
    	
    	int ret = 1;
    	for(int i=idx + 1; i&amp;lt;N; i++) {
    		if(arr[idx] + 1 == arr[i]) {
    			ret = Math.max(ret, solve(i) + 1);
    		}
    	}
    	return cache[idx] = ret;
    }
    
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 시간초과가 발생합니다. 분명 메모이제이션을 활용했다고 생각했지만, 이 문제의 경우 오직 +1 인 값만 메모이제이션이 작동하기에, 실제적으로는 거의 모든 구간을 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;더 이상 풀이가 떠오르지 않아, 다른 분들의 코드를 확인했고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 직접 Position이 뒤 Index에 존재하는지 확인하는 방식이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때, position[] 배열 : 인덱스에 해당하는 숫자가 위치한 인덱스를 저장 하는 것을 통해 문제를 해결함을 알 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1744431232295&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package Main;
import java.io.*;
import java.util.*;

public class Main {
	static int N;
	static int[] arr;
	static int answer = 0;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        
        N = Integer.parseInt(st.nextToken());
        arr = new int[N];
        st = new StringTokenizer(br.readLine());
        
        int[] position = new int[N + 2];
        Arrays.fill(position, -1);
        for(int i=0; i&amp;lt;N; i++) {
        	arr[i] = Integer.parseInt(st.nextToken());
        	position[arr[i]] = i;
        }
        
        for(int i=0; i&amp;lt;N; i++) {
        	int currentNumber = arr[i];
        	int currentPos = i;
        	int length = 1;
        	
        	while(currentNumber + 1 &amp;lt;= N &amp;amp;&amp;amp; position[currentNumber + 1] &amp;gt; currentPos) {
        		currentPos = position[currentNumber +1];
        		currentNumber++;
        		length++;
        	}
        	answer = Math.max(answer, length);
        }
        
        System.out.println(N - answer);
    }
}&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;이런 풀이도 존재하지만, DP 풀이도 존재했습니다.&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;p data-ke-size=&quot;size16&quot;&gt;여기서 dp[i] 배열을 정의하면, 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;dp[i] = dp[i-1] + 1; 이 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1744431549843&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package Main;
import java.io.*;
import java.util.*;

public class Main {
	static int N;
	static int[] arr;
	static int[] dp;
	static int answer = 0;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        
        N = Integer.parseInt(st.nextToken());
        arr = new int[N];
        st = new StringTokenizer(br.readLine());
        
        dp = new int[N+1];
        for(int i=0; i&amp;lt;N; i++) {
        	arr[i] = Integer.parseInt(st.nextToken());
        	dp[arr[i]] = dp[arr[i] - 1] + 1;
        	answer = Math.max(answer, dp[arr[i]]);
        }
        System.out.println(N - answer);
    }
}&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1 style=&quot;background-color: #ffffff; color: #585f69; text-align: start;&quot;&gt;&lt;span&gt;바둑알 점프&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/17492&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/17492&lt;/a&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;한번에 문제를 해결했고, dxdr 과 같이 방향을 정의하는 부분에서, 2차원 배열안에서 (,) 콤마를 작성하지 않는 바람에 약간의 시간소요가 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바의 가변배열에 대하여 다시금 조심해야 함을 느꼈습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1744415027507&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;

public class Main {
	static int N;
	static int[][] map;
	static int[][] dir = {{-1,-1}, {-1,0}, {-1,1}, {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}};
	static boolean answer = false;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        
        map = new int[10][10];
        for(int i=0; i&amp;lt;N; i++) {
        	st = new StringTokenizer(br.readLine());
        	for(int j=0; j&amp;lt;N; j++) {
        		map[i][j] = Integer.parseInt(st.nextToken());
        	}
        }
        
        solve();
        System.out.println(answer == true ? &quot;Possible&quot; : &quot;Impossible&quot;);
    }
    
    static void solve() {
    	if(answer == true) return ;
    	int cnt = 0;
    	for(int i=1; i&amp;lt;map.length-1; i++) {
    		for(int j=1; j&amp;lt;map.length-1; j++) {
    			if(map[i][j] == 2) {
    				cnt += 1;
    			}
    			if(cnt &amp;gt; 1) break;
    		}
    		if(cnt &amp;gt; 1) break;
    	}
    	if(cnt == 1) answer = true;
    	
    	int[][] storeMap = new int[N][N];
    	
    	for(int i=1; i&amp;lt;N-1; i++) {
    		for(int j=1; j&amp;lt;N-1; j++) {
    			//만약 바둑알이 존재하는 곳이라면, 8가지 방향을 살펴보며 확인합니다.
    			if(map[i][j] == 2) {
    				int r = i;
    				int c = j;
    				
    				for(int[] dxdy : dir) {
    					int nr = r + dxdy[0];
    					int nc = c + dxdy[1];
    					if(nr &amp;lt; 1 &amp;amp;&amp;amp; nc &amp;lt; 1 &amp;amp;&amp;amp; nr &amp;gt;= N &amp;amp;&amp;amp; nc &amp;gt;= N) continue;
    					//점프할 공간이 넘치지 않는지 확인합니다.
						int jumpNr = nr + dxdy[0];
						int jumpNc = nc + dxdy[1];
						if(jumpNr &amp;lt; 1 &amp;amp;&amp;amp; jumpNc &amp;lt; 1 &amp;amp;&amp;amp; jumpNr &amp;gt;= N &amp;amp;&amp;amp; jumpNc &amp;gt;= N) continue;
						
    					//만약 점프할 사이 공간에 바둑알이 존재한다면, 점프는 가능하다.
    					if(map[nr][nc] == 2 &amp;amp;&amp;amp; map[jumpNr][jumpNc] == 0) {
    						for(int q=0; q&amp;lt;N; q++) {
    				    		for(int w=0; w&amp;lt;N; w++) {
    				    			storeMap[q][w] = map[q][w];
    				    		}
    				    	}
    						
    						map[r][c] = 0;
    						map[nr][nc] = 0;
    						map[jumpNr][jumpNc] = 2;
    						solve();
    						for(int q=0; q&amp;lt;N; q++) {
    				    		for(int w=0; w&amp;lt;N; w++) {
    				    			map[q][w] = storeMap[q][w];
    				    		}
    				    	}
    					}
    				}
    			}
    		}
    	}
    }
}&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;h1 style=&quot;background-color: #ffffff; color: #585f69; text-align: start;&quot;&gt;&lt;span&gt;병약한 윤호&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/14677&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/14677&lt;/a&gt;&lt;/p&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 이기에 1500개의 약 조합이 주어집니다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제 또한 바로 해결완료했습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1744415119805&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Main {
	static int N;
	static int answer = 0;
	static int[] arr = new int[1501];
	static int[][] cache = new int[1502][1502];
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        
        st = new StringTokenizer(br.readLine());
        String str = st.nextToken();
        
        for(int i=0; i&amp;lt;str.length(); i++) {
        	arr[i] = str.charAt(i) == 'B' ? 0 : str.charAt(i) == 'L' ? 1 : 2;
        }
        
        for(int i=0; i&amp;lt;cache.length; i++) {
        	Arrays.fill(cache[i], -1);
        }
        
        answer = solve(-1, N*3, 0);
        System.out.println(answer);
    }
    
    public static int solve(int left, int right, int turn) {
    	if(left + 1 == right) {
    		return 0;
    	}
    	if(cache[left + 1][right + 1] != -1) {
    		return cache[left + 1][right + 1];
    	}
    	
    	int ret = 0;
    	if(arr[left + 1] == turn) {
    		ret = Math.max(ret, solve(left + 1, right, ( (turn + 1) % 3)) + 1);
    	} 
    	if(arr[right - 1] == turn) {
    		ret = Math.max(ret, solve(left, right - 1, ( (turn + 1) % 3)) + 1);
    	}
    	return cache[left + 1][right + 1] = ret;
    }
    
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1 style=&quot;background-color: #ffffff; color: #585f69; text-align: start;&quot;&gt;&lt;span&gt;컵라면&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/1781&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/1781&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&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, 6, 3, 1, 7, 5, 4 순으로 숙제를 하는데 갑자기 2, 6, 3, 7 번 문제를 시간 내에 풀었다라고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 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;업솔빙 한 과정입니다.&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. pq에 내가 받은 컵라면을 저장합니다. 이떄 오름차순으로 저장합니다.&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;4. 만약 데드라인 이후의 과제인데, 내가 받았던 컵라면 보다 더 많은 컵라면을 준다면, 이 과제를 진행하고, 이전에 진행했던 과제를 하지 않습니다. 이 과정이 가장 &quot;그리디&quot;스러운 방식입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 4번 과정의 사고방식이 가장 중요합니다. (우리는 이미 미래의 컵라면을 알고 있고, 과거의 컵라면을 언제든지 사용하지 않아도 된다는점을 알아야 합니다.)&lt;/p&gt;
&lt;pre id=&quot;code_1744433305835&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package Main;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.StringTokenizer;

public class Main {
	static int N;
	static int[] arr;
	static int[] dp;
	static int answer = 0;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        
        N = Integer.parseInt(st.nextToken());
        int[][] arr = new int[N][2];
        for(int i=0; i&amp;lt;N; i++) {
        	st = new StringTokenizer(br.readLine());
        	arr[i][0] = Integer.parseInt(st.nextToken()); //데드라인
        	arr[i][1] = Integer.parseInt(st.nextToken()); //컵라면 수
        }
        
        Arrays.sort(arr, new Comparator&amp;lt;int[]&amp;gt;() {
        	@Override
        	public int compare(int[] a, int[] b) {
        		if(a[0] == b[0]) {
        			return b[1] - a[1];
        		}
        		return a[0] - b[0];
        	}
        });
        
        //내가 지금까지 받은 컵라면
        PriorityQueue&amp;lt;Integer&amp;gt; pq = new PriorityQueue&amp;lt;&amp;gt;(new Comparator&amp;lt;Integer&amp;gt;() {
        	@Override
        	public int compare(Integer a, Integer b) {
        		return a - b;
        	}
        });
        
        for(int i=0; i&amp;lt;arr.length; i++) {
        	if(pq.size() &amp;lt; arr[i][0]) {
        		pq.add(arr[i][1]);
        	}else if(pq.size() == arr[i][0] &amp;amp;&amp;amp; pq.peek() &amp;lt; arr[i][1]){
        		pq.poll();
        		pq.add(arr[i][1]);
        	}
        }
        
        while(!pq.isEmpty()) {
        	answer += pq.poll();
        }
        
        System.out.println(answer);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;570.&amp;nbsp;Managers&amp;nbsp;with&amp;nbsp;at&amp;nbsp;Least&amp;nbsp;5&amp;nbsp;Direct&amp;nbsp;Reports&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/managers-with-at-least-5-direct-reports/description/?envType=study-plan-v2&amp;amp;envId=top-sql-50&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/managers-with-at-least-5-direct-reports/description/?envType=study-plan-v2&amp;amp;envId=top-sql-50&lt;/a&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;pre id=&quot;code_1744414651560&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/* Write your PL/SQL query statement below */

select e1.name
from employee e1
inner join employee e2 on e1.id = e2.managerid
group by e1.id, e1.name
having count(*) &amp;gt;= 5;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1934.&amp;nbsp;Confirmation&amp;nbsp;Rate&lt;span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://leetcode.com/problems/confirmation-rate/description/?envType=study-plan-v2&amp;amp;envId=top-sql-50&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/confirmation-rate/description/?envType=study-plan-v2&amp;amp;envId=top-sql-50&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 처음에 left outer join을 한뒤 user_id로 grouping 하여 이후 timeout과 confirmed의 개수를 select절에서 센뒤 그값을 분수로 표현하면 된다고 생각했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만, 문제점은 select절에서 case when을 사용하려고 했지만, 그것의 개수를 어떻게 표현하는것에서 막혔습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실패한 쿼리입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1744415354616&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;select s.user_id 
from signups s
left outer join confirmations c on s.user_id = c.user_id
group by user_id;&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;예상대로 CASE WHEN을 사용하였고, group by 에 의해 자동으로 c.action일 경우 1.00, 아닐경우 0.00 으로 더해진뒤 AVG 집계함수로 평균값이 구해집니다.&lt;/p&gt;
&lt;pre id=&quot;code_1744434266648&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;select s.user_id, 
        ROUND(
            AVG(
                CASE 
                    WHEN c.action = 'confirmed' then 1.00
                    else 0
                END
            ), 
            2) as confirmation_rate
from signups s
left outer join confirmations c on s.user_id = c.user_id
group by user_id;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;620.&amp;nbsp;Not&amp;nbsp;Boring&amp;nbsp;Movies&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/not-boring-movies/description/?envType=study-plan-v2&amp;amp;envId=top-sql-50&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/not-boring-movies/description/?envType=study-plan-v2&amp;amp;envId=top-sql-50&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;easy합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오랜만에 쿼리를 작성해서 그런지 id % 2 == 1 로 작성하는 실수를 저질렀습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, descritpion의 경우에도 sql에서 not description = 'boring' 처럼 not 연산자가 떠올라서 어떻게 할지 고민했으나, 심플하게 != 로 작성했습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1744414703406&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;select *
from cinema
where id % 2 = 1 and  description != 'boring'
order by rating desc&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;</description>
      <category>알고리즘/랜덤디펜스</category>
      <author>passionfruit200</author>
      <guid isPermaLink="true">https://passionfruit200.tistory.com/1673</guid>
      <comments>https://passionfruit200.tistory.com/1673#entry1673comment</comments>
      <pubDate>Sat, 12 Apr 2025 08:50:38 +0900</pubDate>
    </item>
    <item>
      <title>[CodeForces] Codeforces Round 1003 (Div. 4) Virtual 후기</title>
      <link>https://passionfruit200.tistory.com/1671</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Codeforces Round 1003 (Div. 4) Virtual 도전 리뷰&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음으로 코드포스에 시도했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A번, B번은 2문제만 풀 수 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;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;단순한 구현은 기본이고, 그 구현을 넘어선 여러 최적화가 필요했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C, D, E, F 까지 Upsolving하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;G까지 Upsolving해보려고 하였는데, 에라토스테네스의체 + 소인수 분해까지는 이해가 가지만, 이를 활용한 핵심로직이 이해가 가지 않아서 포기했습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: center;&quot;&gt;A. Skibidus and Amog'u&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a title=&quot;https://codeforces.com/contest/2065/problem/A&quot; href=&quot;https://codeforces.com/contest/2065/problem/A&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://codeforces.com/contest/2065/problem/A&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레이팅 800 문제입니다. 모든 이름에 'us'가 있으니 'us'를 제거하고 'i'를 붙이면됩니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1744280864589&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Main {
	static int C, N, L, t;
	static int answer = 0;
	static int[] arr;
	public static void main(String[] args) throws IOException{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		
		t = Integer.parseInt(st.nextToken());
		while(t-- &amp;gt; 0) {
			st = new StringTokenizer(br.readLine());
			String w= st.nextToken();
			
			System.out.println(w.substring(0,w.length() - 2) + 'i');
		}
 
	}
}&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: center;&quot;&gt;B. Skibidus and Ohio&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://codeforces.com/contest/2065/problem/B&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://codeforces.com/contest/2065/problem/B&lt;/a&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;하지만, 구현하다보니 만약 연속된 숫자가 1개라도 존재하면 앞뒤에 있는 숫자로 똑같이 바꾸면 반드시 1이됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1744281204803&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Main {
	static int C, N, L, t;
	static int answer = 0;
	static int[] arr;
	public static void main(String[] args) throws IOException{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		
		t = Integer.parseInt(st.nextToken());
		while(t-- &amp;gt; 0) {
			st = new StringTokenizer(br.readLine());
			String w= st.nextToken();
			
			boolean isEnd = false;
			for(int i=0; i&amp;lt;w.length() - 1; i++) {
				if(w.charAt(i) == w.charAt(i + 1)) {
					System.out.println(1);
					isEnd = true;
					break;
				}
			}
			if(!isEnd)
				System.out.println(w.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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: center;&quot;&gt;C1. Skibidus and Fanum Tax (easy version)&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: center;&quot;&gt;쓰여있는것처럼 easy version 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: center;&quot;&gt;이 문제는 빼고 더할 값이 되는 B가 1개이기에, B[0]만 검사하면서&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: center;&quot;&gt;A[i] = A[i];&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: center;&quot;&gt;A[i] = B[0] - A[i];&lt;/span&gt;&lt;/p&gt;
&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;background-color: #ffffff; color: #222222; text-align: center;&quot;&gt;이 2개 중 조건을 만족하는 더 작은값을 선택하면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #222222;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;이런 문제처럼 탐욕적인 문제들이 생각보다 떠올리기 어렵습니다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #222222;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&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;pre id=&quot;code_1744281350236&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Main {
	static int C, N, M, L, t;
	static int answer = 0;
	static int[] A, B;
	public static void main(String[] args) throws IOException{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		
		t = Integer.parseInt(st.nextToken());
		while(t-- &amp;gt; 0) {
			st = new StringTokenizer(br.readLine());
			N = Integer.parseInt(st.nextToken());
			M = Integer.parseInt(st.nextToken());
			
			int[] A = new int[N];
			
			st = new StringTokenizer(br.readLine());
			for(int i=0; i&amp;lt;N; i++) {
				A[i] = Integer.parseInt(st.nextToken());
			}
			
			int[] B = new int[M];
			st = new StringTokenizer(br.readLine());
			for(int i=0; i&amp;lt;M; i++) {
				B[i] = Integer.parseInt(st.nextToken());
			}
			
			A[0] = Math.min(A[0], B[0] - A[0]);
			boolean success = true;
			for(int i=1; i&amp;lt;N; i++) {
				int smallerA = 0, biggerA = 0;
				if(A[i] &amp;gt; B[0] - A[i]) {
					biggerA = A[i];
					smallerA = B[0] - A[i]; 
				}else {
					biggerA = B[0] - A[i];
					smallerA = A[i];
				}
				
				if(A[i-1] &amp;lt;= smallerA) {
					A[i] = smallerA;
				} else if(A[i-1] &amp;lt;= biggerA){
					A[i] = biggerA;
				}else {
					success = false;
					break;
				}
			}
			
			if(success) System.out.println(&quot;YES&quot;);
			else System.out.println(&quot;NO&quot;);
		}
		
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: center;&quot;&gt;C2. Skibidus and Fanum Tax (hard version)&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: center;&quot;&gt;easy version과 다른점은 B가 M개 존재합니다. 이제 비교를 M번 해야겠지요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 핵심은 BinarySearch를 적용할떄, 어떤 기준으로 Search를 해야하는가? 입니다.&lt;/p&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-1] + A[i] 값보다 크거나 같으면서 가장 작은 값을 찾은뒤, 현재 값을 빼고&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1744281609777&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;binarySearchLowerBound(A[i-1] + A[i]) - A[i]; //해당 조건보다 크거나 같은 수 중 가장 작은 수.&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;C1처럼 그리디스럽게 non-decreasing한 배열을 만들어내면 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1744281557163&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Main {
	static int C, N, M, L, t;
	static int answer = 0;
	static int[] A, B;
	public static void main(String[] args) throws IOException{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		StringTokenizer st = new StringTokenizer(br.readLine());
		
		t = Integer.parseInt(st.nextToken());
		StringBuilder sb = new StringBuilder();
		
		while(t-- &amp;gt; 0) {
			st = new StringTokenizer(br.readLine());
			N = Integer.parseInt(st.nextToken());
			M = Integer.parseInt(st.nextToken());
			
			A = new int[N];
			
			st = new StringTokenizer(br.readLine());
			for(int i=0; i&amp;lt;N; i++) {
				A[i] = Integer.parseInt(st.nextToken());
			}
			
			B = new int[M];
			st = new StringTokenizer(br.readLine());
			for(int i=0; i&amp;lt;M; i++) {
				B[i] = Integer.parseInt(st.nextToken());
			}

			Arrays.sort(B);
			A[0] = Math.min(A[0], B[0] - A[0]);
			boolean success = true;
			for(int i=1; i&amp;lt;N; i++) {
				int smallerA = 0, biggerA = 0;
				
				int targetNum = binarySearchLowerBound(A[i-1] + A[i]) - A[i]; //해당 조건보다 크거나 같은 수 중 가장 작은 수.
				if(A[i] &amp;gt; targetNum) {
					smallerA = targetNum;
					biggerA = A[i];
				}else {
					smallerA = A[i];
					biggerA = targetNum;
				}
				
				if(A[i-1] &amp;lt;= smallerA) {
					A[i] = smallerA;
				}else if(A[i-1] &amp;lt;= biggerA) {
					A[i] = biggerA;
				} else {
					success = false;
					break;
				}
			}
			
			if (success) bw.write(&quot;YES\n&quot;);
			else bw.write(&quot;NO\n&quot;);
		}
		bw.flush();
		bw.close();
		br.close();
		
	}
	static int binarySearchLowerBound(int target) {
		int left = -1;
		int right = M - 1 + 1;
		while(left + 1 &amp;lt; right) {
			int mid = (left + right) / 2;
			
			if(B[mid] &amp;lt; target) {
				left = mid;
			} else if(B[mid] &amp;gt;= target){
				right = mid;
			}
		}
		if(right == M) return B[right - 1];
		return B[right];
	}
	
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;업솔빙하려고 했으나, 시간초과가 발생합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; 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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: center;&quot;&gt;D. Skibidus and Sigma&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: center;&quot;&gt;문제 핵심은, 주어진 배열 안의 요소 합이 큰 숫자가 가중치가 높으므로 항상 앞에 와야한다는 것 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: center;&quot;&gt;해당 조건에 맞게 주어진 배열을 정렬한뒤 더해줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: center;&quot;&gt;이때, 직접 모두 더하는 작업을 해주면 시간초과가 발생합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: center;&quot;&gt;식을 정리해서 보면, 아래와 같이 배열의 합이 이후에 나올 원소의 수만큼 계산한뒤 한번에 더해주는걸 알 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1744281987828&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;for(int i=0; i&amp;lt;N; i++) {
    answer += (long) (N - i - 1) * M * sumOfArray(arr[i]);
}
for(int i=0; i&amp;lt;N; i++) {
    answer += score(arr[i]);
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1744281706332&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Main {
	static int C, N, M, L, t;
	static int answer = 0;
	static int[] A, B;
	public static void main(String[] args) throws IOException{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		
		t = Integer.parseInt(st.nextToken());
		while(t-- &amp;gt; 0) {
			st = new StringTokenizer(br.readLine());
			N = Integer.parseInt(st.nextToken());
			M = Integer.parseInt(st.nextToken());
 
			Integer[][] arr = new Integer[N][M];
			
			for(int i=0; i&amp;lt;arr.length; i++) {
				st = new StringTokenizer(br.readLine());		
				for(int j=0; j&amp;lt;M; j++) {
					arr[i][j] = Integer.parseInt(st.nextToken()); 
				}
			}
			
			Arrays.sort(arr, new Comparator&amp;lt;Integer[]&amp;gt;() {
				@Override
				public int compare(Integer[] a, Integer[] b) {
					return Long.compare(sumOfArray(b), sumOfArray(a));
				}
			});
			
			long answer = 0;
			int totalLength = 0;
			for(int i=0; i&amp;lt;N; i++) {
				answer += (long) (N - i - 1) * M * sumOfArray(arr[i]);
			}
			for(int i=0; i&amp;lt;N; i++) {
				answer += score(arr[i]);
			}
			System.out.println(answer);
		}
	}
	
	static long score(Integer[] a) {
	    long ret = 0;
	    for(int i = 0; i &amp;lt; M; i++) {
	        ret += (long) a[i] * (M - i);
	    }
	    return ret;
	}
	static long sumOfArray(Integer[] a) {
		long sum = 0;
		for(int i=0; i&amp;lt;a.length; i++) {
			sum += a[i];
		}
		return sum;
	}
	
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: center;&quot;&gt;E. Skibidus and Rizz&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: center;&quot;&gt;이 문제 또한 보면 바로 완전탐색이 떠올랐습니다만, n과 m의 길이가 2*10^5 이므로 완전탐색은 이미 불가능한점을 알 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&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;background-color: #ffffff; color: #222222; text-align: center;&quot;&gt;해결방안의&amp;nbsp; &lt;/span&gt;가장 핵심은,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. K가 성립할 수 있는가? 를 먼저 판별합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 1번 과정을 통해, 애초에 K가 불가능한 경우를 모두 소거하므로 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;1-1. 만약 Binary String을 N + M 만큼 모두 만들었을떄&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최대 balance-value는 Max(N - M, M - N) 이므로 결국 Math.abs(N-M)과 같다는 것을 알 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 K가 만약 Math.abs(N-M)보다 작다면,&amp;nbsp; 최대값보다 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;1-2. 만약 N을 연속으로 세우고, M을 연속으로 세웠을때의 길이. 즉, 최대 balance-value가 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;2. K가 반드시 성립할 수 있도록 생성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예로들어 0000 으로 세우고 뒤에 101010 으로 유지함으로써&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반드시 조건에 해당하는 Binary String이 만들어질 수 있도록 할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1744282122188&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Main {
	static int C, N, M, L, t, K;
	static int answer = 0;
	static int[] A, B;
	public static void main(String[] args) throws IOException{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		
		t = Integer.parseInt(st.nextToken());
		while(t-- &amp;gt; 0) {
			st = new StringTokenizer(br.readLine());
			N = Integer.parseInt(st.nextToken());
			M = Integer.parseInt(st.nextToken());
			K = Integer.parseInt(st.nextToken());
			StringBuilder sb = new StringBuilder();
			
			//1.[0..Last] 까지 검사했을때 반드시 |N-M|개가 최소 BALANCE입니다.
			if( K &amp;lt; Math.abs(N-M)) {
				System.out.println(&quot;-1&quot;);
				continue;
			}
			//최대 N값보다 K가 더 크다면 불가능
			if( K &amp;gt; Math.max(N, M)) {
				System.out.println(&quot;-1&quot;);
				continue;
			}
			
			//k개의 0을 배치.
			String s =&quot;&quot;;
			if(N &amp;gt; M) {
				for(int i=0; i&amp;lt;K; i++) {
					sb.append(&quot;0&quot;);
				}
				N-=K;
				while(N &amp;gt; 0 &amp;amp;&amp;amp; M &amp;gt; 0) {
					sb.append(&quot;10&quot;);
					M -= 1;
					N -= 1;
				}
				while(M &amp;gt; 0) {
					sb.append(&quot;1&quot;);
					M -=1;
				}
			} else {
				for(int i=0; i&amp;lt;K; i++) {
					sb.append(&quot;1&quot;);
				}
				M-=K;
				while(N &amp;gt; 0 &amp;amp;&amp;amp; M &amp;gt; 0) {
					M -= 1;
					N -= 1;
					sb.append(&quot;01&quot;);
				}
				while(N &amp;gt; 0) {
					sb.append(&quot;0&quot;);
					N-=1;
				}
			}
			
			System.out.println(sb);
		}
	}
	
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: center;&quot;&gt;F. Skibidus and Slay&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: center;&quot;&gt;이 문제 또한, 완전탐색으로 각 정점을 모두 순회하면서 나올 수 있는 모든 경우를 탐색하면 나오는 숫자가 Majority인 경우를 구할 수 있습니다. 역시나 시간초과가 존재합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;문제 풀이 핵심은,&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;[i, i]&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;[i, x, i]&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;이 2가지의 경우에만 Majority가 될 수 있다는 것을 알아야합니다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;만약&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;[i, x, i, i]라면 어떻게 할건가요? 라고할 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;이는 이미 [2..3] 에서 [i, i]가 나온것을 알 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;[i, x, i, x, i]도 마찬가지입니다.&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: center;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;그리고 answer값을 애초에 모두 0 으로 바꾸고, majority인 숫자를 HashMap으로 Counting해가며 &amp;gt;=2 인경우 1로 바꿔나가는점이 기억에 남습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;저라면, HashMap 대신에 범위 배열을 사용했을 것 같은데, 그러면 너무 비효율적이었겠네요.&lt;/p&gt;
&lt;pre id=&quot;code_1744282585201&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Main {
	static int T, N;
	static List&amp;lt;Integer&amp;gt;[] adj;
	static StringBuilder sb = new StringBuilder();
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        
        T = Integer.parseInt(st.nextToken());
        while (T-- &amp;gt; 0) {
        	st = new StringTokenizer(br.readLine());
        	N = Integer.parseInt(st.nextToken());
        	
        	int[] A = new int[N];
        	st = new StringTokenizer(br.readLine());
        	for(int i=0; i&amp;lt;N; i++) {
        		A[i] = Integer.parseInt(st.nextToken()) - 1;
        	}
        	
        	adj = new ArrayList[N];
        	for(int i=0; i&amp;lt;adj.length; i++) {
        		adj[i] = new ArrayList&amp;lt;Integer&amp;gt;();
        	}
        	
        	for(int i=0; i&amp;lt;N-1; i++) {
        		st = new StringTokenizer(br.readLine());
        		int u = Integer.parseInt(st.nextToken()) - 1;
        		int v = Integer.parseInt(st.nextToken()) - 1;
        		adj[u].add(v);
        		adj[v].add(u);
        	}
        	
        	char[] answer = new char[N];
        	Arrays.fill(answer, '0');
        	
        	for(int u=0; u&amp;lt;N; u++) {
        		Map&amp;lt;Integer, Integer&amp;gt; countMap = new HashMap&amp;lt;&amp;gt;();
        		for(int v : adj[u]) {
        			countMap.put(A[v], countMap.getOrDefault(A[v], 0) + 1);
        		}
        		countMap.put(A[u], countMap.getOrDefault(A[u], 0) + 1);
        		
        		for(Map.Entry&amp;lt;Integer, Integer&amp;gt; entry : countMap.entrySet()) {
        			int value = entry.getKey();
        			int count = entry.getValue();
        			if(count &amp;gt;= 2) {
        				answer[value] = '1';
        			}
        		}
        	}
        	sb.append(answer).append('\n');
        }
        System.out.println(sb);
    }
 
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: center;&quot;&gt;G. Skibidus and Capping&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Upsolving하다가 포기했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저, 에라토스테네스의 체를 활용해 소인수 분해를 하는 것까지는 이해했습니다만, 그 이후의 lcm이나 여러 조건들이 합쳐지면서 아직까진 눈에 보이지 않습니다. (업솔빙하면서 피곤해서 그럴수도 있습니다.)&lt;/p&gt;
&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;pre id=&quot;code_1744282918350&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;

public class Main {
	static int N;
	static int[] minFactor = new int[200002];
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder result = new StringBuilder();
        
        N = Integer.parseInt(br.readLine());
        System.out.print(result);
    }
    
    static void eratosthenes() {
    	minFactor[0] = -1;
    	minFactor[1] = -1;
    	for(int i=2; i &amp;lt; minFactor.length; i++) {
    		minFactor[i] = i;
    	}
    	int sqrtN = (int) Math.sqrt((double) minFactor.length);
    	for(int i=2; i&amp;lt;=sqrtN; i++) {
    		for(int j=i*i; j&amp;lt;=minFactor.length; j+=i) {
    			if(minFactor[j] == j)
    				minFactor[j] = i;
    		}
    	}
    }
    
    static List&amp;lt;Integer&amp;gt; factor(int n){
    	List&amp;lt;Integer&amp;gt; ret = new ArrayList&amp;lt;&amp;gt;();
    	while(n &amp;gt; 1) {
    		ret.add(minFactor[n]);
    		n /= minFactor[n];
    	}
    	return ret;
    }
}&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;저는 에라토네스의 체로 구현했지만, 사실 에라토스테네스의 체 대신에 더 빠른 구현에서는 factor 함수에서 바로 구하는 것이 훨씬 간단합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1744282980141&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 소인수 분해: 정수 x를 소인수 분해해서 리스트에 저장
static List&amp;lt;Integer&amp;gt; primeFactors(int x) {
    List&amp;lt;Integer&amp;gt; pf = new ArrayList&amp;lt;&amp;gt;();
    for (int i = 2; i * i &amp;lt;= x; i++) {
        while (x % i == 0) {
            pf.add(i);
            x /= i;
        }
    }
    if (x &amp;gt; 1) pf.add(x); // 마지막으로 남은 소수
    return pf;
}&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;p data-ke-size=&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>알고리즘/codeforces</category>
      <author>passionfruit200</author>
      <guid isPermaLink="true">https://passionfruit200.tistory.com/1671</guid>
      <comments>https://passionfruit200.tistory.com/1671#entry1671comment</comments>
      <pubDate>Thu, 10 Apr 2025 20:03:25 +0900</pubDate>
    </item>
    <item>
      <title>[LeetCode] 210. Course Schedule II - 위상정렬(TopologicalSort) JAVA</title>
      <link>https://passionfruit200.tistory.com/1658</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/course-schedule-ii/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/course-schedule-ii/&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;코드설명&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위상정렬(TopologicalSort)을 활용합니다.&lt;/p&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를 활용하여 위상정렬을 구현하는 것은 어렵지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중요한점은, 어디에서 시작하든지 간에 위상정렬을 구할 수 있기에, inDegree를 계산할 필요가 없다는점을 유의합니다.&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;예시 2번의, order : [0, 2, 1, 3] 의 정렬을 구했다고 가정하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 이러한 위상 정렬이 의미하는 것은, 순서대로 그래프가 DAG(Directed ACyclic Graph)의 순서를 나타냄을 알 수 있습니다.&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;아래의 코드를 통해, 사이클일 경우 빈 배열을 반환합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1741503019171&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;for(int i=0; i&amp;lt;NumCourses; i++){
	for(int j=i+1; j&amp;lt;NumCourses; j++){
    	ArrayList&amp;lt;Integer&amp;gt; graphOfJ = graph.get(order.get(j));
        for(int k=0; k&amp;lt;graphOfJ.size(); k++){
        	if(order.get(i) == graphOfJ.get(k)){
            	return new ArrayList&amp;lt;Integer&amp;gt;();
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;코드&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정답코드1입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1741502639618&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution {
    boolean[] seen;
    ArrayList&amp;lt;ArrayList&amp;lt;Integer&amp;gt;&amp;gt; graph;
    ArrayList&amp;lt;Integer&amp;gt; order;
    int NumCourses;
    int[][] Prerequisites;
    public int[] findOrder(int numCourses, int[][] prerequisites) {
        NumCourses = numCourses;
        Prerequisites = prerequisites;
        graph = new ArrayList&amp;lt;ArrayList&amp;lt;Integer&amp;gt;&amp;gt;();
        for(int i=0; i&amp;lt;numCourses; i++){
            graph.add(new ArrayList&amp;lt;Integer&amp;gt;());
        }
        for(int i=0; i&amp;lt;Prerequisites.length; i++){
            int a = Prerequisites[i][0];
            int b = Prerequisites[i][1];
            graph.get(b).add(a);
        }
        List&amp;lt;Integer&amp;gt; sorted = topologicalSort();
        int[] answer = new int[sorted.size()];
        for(int i=0; i&amp;lt;sorted.size(); i++){
            answer[i] = sorted.get(i);
        }
        return answer;
    }

    void DFS(int here){
        seen[here] = true;
        ArrayList&amp;lt;Integer&amp;gt; connected = graph.get(here);
        for(int i=0; i&amp;lt;connected.size(); i++){
            if(seen[connected.get(i)] == false){
                DFS(connected.get(i));
            }
        }
        order.add(here);
    }

    List&amp;lt;Integer&amp;gt; topologicalSort(){
        seen = new boolean[NumCourses];
        order = new ArrayList&amp;lt;Integer&amp;gt;();
        for(int i=0; i&amp;lt;NumCourses; i++){
            if(seen[i] == false){
                DFS(i);
            }
        }
        Collections.reverse(order);
        for(int i=0; i&amp;lt;NumCourses; i++){
            for(int j=i+1; j&amp;lt;NumCourses; j++){
                //j번째가 i를 바라보는경우가 있을경우 실패입니다.
                ArrayList&amp;lt;Integer&amp;gt; graphOfJ = graph.get(order.get(j));
                for(int k=0; k&amp;lt;graphOfJ.size(); k++){
                    if(graphOfJ.get(k) == order.get(i)){
                        return new ArrayList&amp;lt;&amp;gt;();
                    }
                }
            }
        }
        return order;
    }
}&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;처음에 작성한 오답크도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;numCourses = 3, prerequisite = [[1, 0], [1, 2], [0, 1]] 에 대해서 일종의 사이클이 발생하여 [] 를 반환해야합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보시면 알겠지만, 1번 Course 수업을 듣기 위해서는 0번 수업을 듣고 들어야하고, 0번 수업을 듣기 위해서는 1번 수업을 듣고 들어야 합니다. 불가능한 경우라는 것을 알 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1741498045610&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution {
    ArrayList&amp;lt;ArrayList&amp;lt;Integer&amp;gt;&amp;gt; graph = new ArrayList&amp;lt;&amp;gt;();
    int[] inDegree;
    public int[] findOrder(int numCourses, int[][] prerequisites) {
        visited = new boolean[numCourses];
        for(int i=0; i&amp;lt;numCourses; i++){
            graph.add(new ArrayList&amp;lt;Integer&amp;gt;());
        }

        inDegree = new int[numCourses];
        for(int i=0; i&amp;lt;prerequisites.length; i++){
            int a = prerequisites[i][0];//진입차수 위치
            int b = prerequisites[i][1];//진출차수 위치
            graph.get(b).add(a);
            inDegree[a] += 1;
        }

        int startIdx = 0;
        for(int i=0; i&amp;lt;inDegree.length; i++){
            //inDegree는 
            if(inDegree[i] == 0){
                startIdx = i;
                DFS(startIdx);
            }
        }
        
        Collections.reverse(ret);
        int[] answer = new int[ret.size()];
        int idx = 0;
        for(int v : ret){
            answer[idx++] = v;
        }
        return answer;
    }
    List&amp;lt;Integer&amp;gt; ret = new ArrayList&amp;lt;Integer&amp;gt;();
    boolean[] visited;
    public void DFS(int idx){
        ArrayList&amp;lt;Integer&amp;gt; node = graph.get(idx);
        for(int i=0; i&amp;lt;node.size(); i++){
            int next = node.get(i);
            if(visited[next] == false){
                visited[next] = true;
                DFS(next);
            }
        }
        ret.add(idx);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/LeetCode</category>
      <author>passionfruit200</author>
      <guid isPermaLink="true">https://passionfruit200.tistory.com/1658</guid>
      <comments>https://passionfruit200.tistory.com/1658#entry1658comment</comments>
      <pubDate>Sun, 9 Mar 2025 11:51:51 +0900</pubDate>
    </item>
    <item>
      <title>[LeetCode] 134. Gas Station - 탐욕법(그리디, Greedy) JAVA</title>
      <link>https://passionfruit200.tistory.com/1657</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/gas-station/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/gas-station/&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;코드설명&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;탐욕법(그리디, Greedy)을 활용합니다.&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;문제의 핵심은, totalGas 가 totalCost보다 반드시 커야만, 원래의 시작점으로 돌아올 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;또한, 이동처리를 하면서 currentGas가 &amp;lt; 0 이 되는 경우가 발생하는데, 이때는 0~해당 위치까지 모두 CircularRoute가 불가능합니다. (gas와 cost가 누적으로 계산되기 때문입니다.)&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그러므로, 0에서부터만 n까지만 처리해도 가능한 것 입니다. (물론, totalGas가 totalCost보다 크다면 반드시 순회가 가능하다는 조건이 있게 그렇습니다.)&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;코드&lt;/h2&gt;
&lt;pre id=&quot;code_1741506280177&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution {
    public int canCompleteCircuit(int[] gas, int[] cost) {
        int totalGas = 0;
        int totalCost = 0;
        int currentGas = 0;

        int startIdx = 0;
        for(int i=0; i&amp;lt;gas.length; i++){
            totalGas += gas[i];
            totalCost += cost[i];
            currentGas += gas[i] - cost[i];
            if(currentGas &amp;lt; 0){
                currentGas =0;
                startIdx = i + 1;
            }
        }
        return totalGas &amp;gt;= totalCost ? startIdx : -1;
    }
}&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;시간초과가 발생하는 코드입니다. O(N^2) 이기에 10^10 입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1741503630164&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution {
    public int canCompleteCircuit(int[] gas, int[] cost) {
        
        int gasLength = gas.length;
        for(int startStation = 0; startStation &amp;lt; gasLength; startStation++){
            int tank = gas[startStation];
            boolean isTravelBack = true;
            for(int i=startStation; i &amp;lt; startStation + gasLength; i++){
                tank += -cost[i % gasLength]; 
                if(tank &amp;lt; 0){
                    isTravelBack = false;
                    break;
                }
                tank += gas[(i + 1) % gasLength];
            }
            if(isTravelBack == true){
                return startStation;
            }
        }
        return -1;
   }
}&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>알고리즘/LeetCode</category>
      <author>passionfruit200</author>
      <guid isPermaLink="true">https://passionfruit200.tistory.com/1657</guid>
      <comments>https://passionfruit200.tistory.com/1657#entry1657comment</comments>
      <pubDate>Sun, 9 Mar 2025 11:51:45 +0900</pubDate>
    </item>
    <item>
      <title>[LeetCode] 236. Lowest Common Ancestor of a Binary Tree - 깊이우선탐색(DFS) JAVA</title>
      <link>https://passionfruit200.tistory.com/1656</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/description/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/description/&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;코드설명&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;깊이우선탐색(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;아래 정답코드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의 경우, root가 NULL이냐 아니냐에 따라 p인지 q인지 판단합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 만약 왼쪽 트리에서 NULL이 아니고, 오른쪽 트리에서 NULL이 반환된다면, 왼쪽트리가 반드시 LCA임을 알 수 있습니다. 왼쪽 자식 트리가 NULL이 아닌데, P 혹은 Q인데, 오른쪽 자식트리가 NULL이라면, 당연히 LCA입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LCA에서의 트리 성질을 이해한다면 풀이가 가능한 방식입니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;코드&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정답코드1입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1741508676070&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    TreeNode P, Q, Root;
    TreeNode answer;
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        Root = root; P = p; Q = q;
        DFS(root);
        return answer;
    }

    boolean DFS(TreeNode root){
        boolean isCenterDescendant = false, isLeftDescendant = false, isRightDescendant = false;
        if(root == P || root == Q){
            isCenterDescendant = true;
        }
        if(root.left != null){
            isLeftDescendant |= DFS(root.left);
        }
        if(root.right != null){
            isRightDescendant |= DFS(root.right);
        }
        if( (isCenterDescendant &amp;amp; isLeftDescendant) | (isCenterDescendant &amp;amp; isRightDescendant) | (isLeftDescendant &amp;amp; isRightDescendant)){
            answer = root;
        }
        if(isLeftDescendant | isRightDescendant | isCenterDescendant) return true;
        return 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;정답코드2입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드의 경우 특이점은, 만약 왼쪽 트리에만 값이 반횐되고, 오른쪽 트리가 NULL이라면, 왼쪽트리가 반드시 LCA입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1741509858423&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        //기저 사례 : root가 null이거나 p 또는 q 중 하나와 같으면 root 반환
        if(root == null || root == p || root == q){
            return root;
        }

        //왼쪽과 오른쪽 서브트리 탐색
        TreeNode left = lowestCommonAncestor(root.left, p, q);
        TreeNode right = lowestCommonAncestor(root.right, p, q);

        //양쪽에서 p, q를 찾았으면 현재 노드가 LCA
        if(left != null &amp;amp;&amp;amp; right != null){
            return root;
        }

        //p와 q가 한쪽 서브트리에만 있는 경우, 해당 서브트리의 결과를 반환
        return (left != null) ? left:right;
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>알고리즘/LeetCode</category>
      <author>passionfruit200</author>
      <guid isPermaLink="true">https://passionfruit200.tistory.com/1656</guid>
      <comments>https://passionfruit200.tistory.com/1656#entry1656comment</comments>
      <pubDate>Sun, 9 Mar 2025 11:51:39 +0900</pubDate>
    </item>
    <item>
      <title>[LeetCode] 322. Coin Change - 동적계획법(Dynamic Programming) JAVA</title>
      <link>https://passionfruit200.tistory.com/1655</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/coin-change/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/coin-change/&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;코드설명&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동적계획법(Dynamic Programming) 을 활용합니다.&lt;/p&gt;
&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;최대개수를 구할때는 0으로 초기값을 설정하고, MAX값으로 갱신하면 되고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최소개수를 구할때는 amount로 초기값을 설정하고, MIN 값으로 갱신하면됩니다.&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;또한, ret에서 ret에 누적값을 더하는것이 아닌, 아래처럼 값으로 최소값으로 갱신시키는 이유는 무엇일까요?&lt;/p&gt;
&lt;pre id=&quot;code_1741513945909&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ret1 = Math.min(ret1, knapsack(coinIdx, amount - Coins[coinIdx]) + 1);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이유는 최소값을 계속해서 갱신하기 위해서입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 ret1 += 로 처리했다면, 이전값이 현재값에 영향을 미치는데 그렇게 되면 최소 동전의 개수를 못구하게 됩니다. 즉, 모든 동전의 개수로 amount를 만들 수 있는 모든 경우의 수를 구하게 되겠지요.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;코드&lt;/h2&gt;
&lt;pre id=&quot;code_1741513691211&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution {
    int[] Coins;
    int[][] cache;
    int Amount;
    final int MAXAMOUNT = 10001;
    public int coinChange(int[] coins, int amount) {
        Coins = coins; Amount = amount;
        cache = new int[coins.length][MAXAMOUNT + 1];
        for(int i=0; i&amp;lt;coins.length; i++){
            Arrays.fill(cache[i], -1);
        }
        int answer = knapsack(0, amount);
        return answer &amp;gt; amount ? -1 : answer;
    }

    int knapsack(int coinIdx, int amount){
        if(amount == 0){
            return 0;
        }
        if(cache[coinIdx][amount] != -1) return cache[coinIdx][amount];
        int ret1 = MAXAMOUNT;
        if(coinIdx &amp;lt; Coins.length &amp;amp;&amp;amp; amount - Coins[coinIdx] &amp;gt;= 0)
            ret1 = Math.min(ret1, knapsack(coinIdx, amount - Coins[coinIdx]) + 1);

        if(coinIdx + 1 &amp;lt; Coins.length)
            ret1 = Math.min(ret1, knapsack(coinIdx + 1, amount));

        return cache[coinIdx][amount] = ret1;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/LeetCode</category>
      <author>passionfruit200</author>
      <guid isPermaLink="true">https://passionfruit200.tistory.com/1655</guid>
      <comments>https://passionfruit200.tistory.com/1655#entry1655comment</comments>
      <pubDate>Sun, 9 Mar 2025 11:51:35 +0900</pubDate>
    </item>
  </channel>
</rss>