[ 백준 ] 2725 / 보이는 점의 개수

金弘均·2021년 9월 15일
0

Baekjoon Online Judge

목록 보기
94/228
post-thumbnail

# Appreciation

/*
 * Problem :: 2725 / 보이는 점의 개수
 *
 * Kind :: Math + Dynamic Programming
 *
 * Insight
 * - (4,2)는 (0,0)에서 보이지 않는다
 *   (0,0)과 (4,2)를 연결하는 직선이 (2,1)을 통과하기 때문이다
 *   + 좌표 (x,y) 가 있을 때
 *     이 좌표가 보이기 위해서는 gcd(x,y)=1 이어야 한다!
 *
 * Point
 * - 테스트 케이스에서 N 이 주어질 때마다
 *   NxN 의 모든 좌표를 보고 gcd(x,y)=1 인 좌표수를 구했는데...
 *   답은 맞지만 시간초과에 걸렸다
 *   O(T*N^2) = O(10^9) 이니 그럴 수밖에 없다
 *   + 그러고보니 max(N)=1000 이니
 *     1000x1000 좌표공간을 설정해놓고
 *     보이는 좌표를 모두 체크한 다음에
 *     주어지는 N 의 범위에 맞춰서 세어주면 되겠다!
 *     # 근데 이 방법도 결국 탐색한 곳을 또 탐색해야하서 비효율적이다
 *       (1000개 테스트 케이스에서 N=1000 인 입력이 들어온다고 하면...)
 *       dp[i] = N=i 일 때, NxN 좌표공간에서 보이는 점의 개수
 *       라고 한다면, 이를 이용해서 dp[i+1] 을 구할 수 없을까?
 *       -> dp[i+1] = N=i+1 일 때, (N+1)x(N+1) 좌표공간에서 보이는 점의 개수
 *                  = NxN 좌표공간에서 보이는 점의 개수
 *                    + (1,N+1), (2,N+1), ..., (N,N+1) 에서 보이는 점의 개수
 *                    + (N+1,1), (N+1,2), ..., (N+1,N) 에서 보이는 점의 개수
 *                  = dp[i]
 *                    + (1,N+1), (2,N+1), ..., (N,N+1) 에서 보이는 점의 개수
 *                    + (N+1,1), (N+1,2), ..., (N+1,N) 에서 보이는 점의 개수
 *          => 역시 DP 다...
 *
 * - 또 하나 중요한점
 *   + 대칭이다!!!
 *     # y=x 직선 기준 위쪽이나 아래쪽의 한쪽만 검사하면
 *       검사안한 나머지 한쪽의 좌표들도 보이는지 알 수 있다
 *       -> 좌표 i != j 인 (i,j) 가 보이면 (j,i) 도 보이는 좌표이다
 */

# Code

//
//  BOJ
//  ver.C++
//
//  Created by GGlifer
//
//  Open Source

#include <iostream>
#include <cstring>
#include <numeric>

using namespace std;

#define endl '\n'

// Set up : Global Variables
/* None */

// Set up : Functions Declaration
/* None */


int main()
{
    // Set up : I/O
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    // Process
    /* isVisible[i][j] = 좌표 (i,j) 가 보이면 true
     *                   좌표 (i,j) 가 보이지 않으면 false */
   bool isVisible[1000+1][1000+1];
   memset(isVisible, false, sizeof(isVisible));
   isVisible[0][1] = isVisible[1][0] = isVisible[1][1] = true;

   for (int i=2; i<=1000; i++) {
       for (int j=1; j<i; j++) {
           int g = gcd(i, j);
           if (g == 1) { /* i 와 j 의 최대공약수가 1 이면 */
               /* 좌표 (i,j) 와 (j,i) 는 보이는 점임 */
               isVisible[i][j] = isVisible[j][i] = true;
           }
       }
   }

   long dp[1000+1];
   dp[1] = 3; /* N=1 */
   for (int i=2; i<=1000; i++) {
       dp[i] = dp[i-1];
       /* (N+1,1), (N+1,2), ..., (N+1,N) 에서 보이는 점의 개수 검사 */
       for (int j=1; j<i; j++) {
           if (isVisible[i][j]) {
               dp[i] += 2; /* (i,j) 가 보이면 (j,i) 도 보임 */
           }
       }
   }

   // Set up : Input
   int C; cin >> C;

   while (C--) {
       int N; cin >> N;

       // Control : Output
       cout << dp[N] << endl;
   }
}

// Helper Functions
/* None */
profile
이런 미친 게임을 봤나! - 옥냥이

0개의 댓글