이 문제를 [백준 1202] 보석도둑에서의 lower_bound를 이용한 풀이와 비슷하게 시도해보고자 한다.

lower\_bound(x): x이상의 수 중 최솟값 인데

순회강연의 문제에서는 각 강연의 endline이 주어지고, 그 endline안에만 강연을 할 수 있다.

즉 day=2일때, endlined이 2이하인 강연만 할 수 있어서 정확히 lower_bound의 정의에 반대이다.


여기서 중요한것이 정확히 lower_bound의 반대라는 점인데,

그렇다면 각 케이스에서 가장 큰 endline을 maxEndline이라고 했을 때,

endline = maxEndline - endline;

이 상태에서는 "lower_bound(x'): x'이하의 수중 최댓값"이 된다.

따라서, day=2일때, lower_bound(day)의 결과는 endline이 2 이하인 강연 중 비용이 가장 큰 것의 index가 나오게 된다.


이 풀이는 뭔가 머릿속으로는 이해가 되는데, 말로 하려니깐 정의자체가 어려운것같다.

#include <bits/stdc++>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<pair<int, int> > vpii;

// INT_MAX = 2^31 ~= 2.1e9
// LLONG_MAX = 2^63 ~= 9.2e18

const int MAX=(int)1e4;
pii lecture[MAX+5]; // <비용, 기간>
multiset<int> day;

int main(){
  int n;
  scanf("%d", &n);

  int nDay=0;
  for(int i=0; i<n; i++){
    scanf("%d %d", &lecture[i].first, &lecture[i].second);
    if(lecture[i].second>nDay) nDay=lecture[i].second;
  }
  for(int i=0; i<n; i++){
    lecture[i].second=nDay-lecture[i].second;
  }
  for(int i=0; i<nDay; i++) day.insert(i);

  sort(lecture, lecture+n, greater<pii>()); // 비용이 큰 순으로 정렬을 한다.

  ll answer=0;
  for(int i=0; i<n; i++){ // i는 강연의 순번, 비용이 높은것이 먼저 나온다.
    auto iter=day.lower_bound(lecture[i].second);
    if(iter!=day.end()){
      // 값을 찾았다면 비용을 더해주고, 해당 날은 제거한다.
      answer+=lecture[i].first;
      day.erase(iter);
    }
  }
  printf("%lld", answer);
  return 0;
}

'프로그래밍 > PS' 카테고리의 다른 글

[백준] Class 3 All Solved  (0) 2021.06.03
[백준 12904] A와 B  (0) 2021.05.28
[백준 14500] 테트로미노  (0) 2021.03.25
[백준] 골드V 달성  (0) 2021.03.24
[백준 17404번] RGB거리 2  (0) 2021.03.19

ps에서 c++을 사용하는 사람들 중 입력을 받을 때, 'cin'으로 입력을 받는 사람들은 대부분 시간을 단축하기 위해서

int main(){
  ios_base::sync_with_stdio(false);
  cin.tie(nullptr);
}

이런 trick을 사용한다.

하지만 문제를 푸는 도중에 문제의 입력을 색다른 방법으로 받아야 할 때가 있다.

2667번: 단지번호붙이기
2178번: 미로 탐색

위와 같은 경우들인데, 각 cell의 숫자들이 연속해서 입력되고 있다.

이것을 입력받기 위해서는 여러 가지 방법을 사용할 수 있는데,

내가 간단하게 사용하는 방법은 한자리씩 int형으로 입력받는 방법이다.

scanf("%1d", &a[x][y]);

이렇게 scanf를 사용하면서도 위의 trick을 지우지 않고 cin을 사용한다면 입력을 받을 때 오류가 발생한다.

이것 때문에 틀리지 않아도 되는 문제를 여러 번 틀렸다.

결론은, scanf를 사용할 때에

ios_base::sync_with_stdio(false);

이것은 꼭 주석처리 해 주어야 한다.

test-case가 주어지는 문제를 풀 때 가끔씩 전역변수로 선언된 vector을 케이스마다 새롭게 사용해야 하는 경우가 있다.

#include<bits/stdc++.h>
vector<int> a(20001);
...
int main(){
  ...
  int t;
  cin>>t;
  while(t--){
    ...
    for(int i=0; i<n; i++){
      cin>>a[i];
    }
    ...
  }
  ...
}
    

위의 경우와 같이 전역변수 vector<int> a에 test-case마다 새로 값을 입력받아야 할 때에는,

test-case가 끝날 때 마다 전역변수 a의 값들을 초기화해주어야 한다.

이럴 때 자주 사용하는것은 

a.clear()

이것일 것이다.

하지만 

codingdog.tistory.com/entry/c-vector-clear-size를-0으로-만들어-준다

 

c++ vector clear 함수 : size를 0으로 만들어 준다.

 안녕하세요. chogahui05입니다. ps를 하시다 보면, 테스트 케이스 문제를 많이 보셨을 겁니다. 보통, vector를 클리어 할 때, clear 메소드를 많이 이용하고요. 여기서 한 가지 질문. clear 메소드는 정말

codingdog.tistory.com

이 블로그의 글에 따르면 완벽하게 초기화 되지 않는다.

이것을 보완하여 완벽한 초기화를 하기 위해서

swap trick을 사용해주면 된다. 위의 예시를 활용해보자면

#include<bits/stdc++.h>
vector<int> a(20001);
...
int main(){
  ...
  int t;
  cin>>t;
  while(t--){
    ...
    for(int i=0; i<n; i++){
      cin>>a[i];
    }
    ...
    vector<int>(20001).swap(a);
  }
  ...
}
    

만약 이차원 vector라도 동일하게 사용해주면 된다.

#include<bits/stdc++.h>
vector< vector<int> > a(20001);
...
int main(){
  ...
  int t;
  cin>>t;
  while(t--){
    ...
    for(int i=0; i<n; i++){
      cin>>a[i];
    }
    ...
  }
  ...
  vector< vector<int> >(20001).swap(a);
}
    
int main(){
    int arr[1025][1025]={0,};
    int d[1025][1025]={0,};
    
    ...
    
    for(int i=1; i<=n; i++){
      for(int j=1; j<=n; j++){
      	d[i][j]=10 // 상수대입
        d[i][j]=d[i-1][j]+d[i][j-1]-d[i-1][j-1]+arr[i][j]; // dp연산
      }
    }
    
    ...
}

main함수에서 arr배열과 d배열을 모두 1025*1025*sizeof(int)의 크기로 선언을 한 뒤

두 배열에 모두 값을 할당할 때, 

d[i][j]=10과 같이 상수를 대입했을 때에는 오류가 없었지만

d[i][j]=d[i-1][j]+d[i][j-1]-d[i-1][j-1]+arr[i][j]; 와 같이 dp연산을 했을 때에는 segmentation fault가 발생하였다.

 

d배열을 전역변수에 선언하고 dp연산을 했을 때에는 오류가 발생하지 않는것으로 보아서

이 상황에서 오류가 발생한 원인은 매우 큰 두개의 지역변수로 인해서 스택메모리가 초과하여 발생한 오류로 보인다.

앞으로는 매우 큰 배열변수를 선언할 때에는 전역변수에 선언하는게 나을 것 같다.

이 문제는 어렵지 않은 하드코딩 문제이지만, 디버깅을 하는 과정에서 항상 놓치고 있던 것을 머릿속에 각인시키고자 글을 쓴다.

 

전략


내가 문제에 사용한 전략은 아래와 같다.

1. 모든 원소마다 19개의 테트로미노의 최댓값을 비교한다.

2. 테트로미노의 시작점은 최대한 좌측 상단에 있는 정사각형이다.

3. 시작점으로부터 가장 왼쪽에 있는 정사각형과의 거리에 따라서 type을 정한다.

    ->가장 왼쪽에 있는 사각형의 index가 0보다 작지 않게 하기 위해서

4. 모든 원소에 초깃값으로 매우 큰 음수값을 넣어서 경계를 신경 쓰지 않도록 한다.

 

이러한 전략을 적용한 테트로미노 19개의 모양은 아래와 같다.

위와 같은 전략을 사용하여 코딩을 했을 때, 대부분의 경우는 옳은 답이 나온다.

디버깅


하지만, 4번의 전략으로 오른쪽, 아래쪽 경계를 신경쓰지 않았기 때문에
주어진 배열의 크기인 n,m이 최대치인 500일 경우, 경계를 넘는 값을 참조하여 틀린 값들이 나왔다.

예를 들어, 아래와 같은 배열이 주어졌을 때

경곗값을 검사하지 않았기 때문에, 테트로미노가 아래와 같이 위치하는 경우도 생겼다.

이러한 경우들을 방지하기 위해서 처음에 잡아놓는 배열의 크기를 503(최대로 참조할 수 있는 범위) 로 늘렸고,

503의 index까지 초깃값을 -4000으로 세팅해주었다.

코드


#include <bits/stdc++.h>
#define MAX 500

using namespace std;
int a[MAX+2][MAX+2];

int type0(int i, int j){
  // 해당 행/열 반대방향으로 블럭이 없는경우
  int maxCount=0;
  int cnt;
  
  //1
  cnt = a[i][j]+a[i][j+1]+a[i+1][j]+a[i+1][j+1];
  if(maxCount<cnt) maxCount=cnt;

  //2
  cnt = a[i][j]+a[i][j+1]+a[i][j+2]+a[i][j+3];
  if(maxCount<cnt) maxCount=cnt;

  //3
  cnt = a[i][j]+a[i+1][j]+a[i+2][j]+a[i+3][j];
  if(maxCount<cnt) maxCount=cnt;

  //4
  cnt = a[i][j]+a[i+1][j]+a[i+2][j]+a[i+2][j+1];
  if(maxCount<cnt) maxCount=cnt;

  //5
  cnt = a[i][j]+a[i][j+1]+a[i][j+2]+a[i+1][j];
  if(maxCount<cnt) maxCount=cnt;

  //6
  cnt = a[i][j]+a[i][j+1]+a[i+1][j+1]+a[i+2][j+1];
  if(maxCount<cnt) maxCount=cnt;

  //9
  cnt = a[i][j]+a[i+1][j]+a[i+1][j+1]+a[i+1][j+2];
  if(maxCount<cnt) maxCount=cnt;

  //10
  cnt = a[i][j]+a[i][j+1]+a[i+1][j]+a[i+2][j];
  if(maxCount<cnt) maxCount=cnt;

  //11
  cnt = a[i][j]+a[i][j+1]+a[i][j+2]+a[i+1][j+2];
  if(maxCount<cnt) maxCount=cnt;

  //12
  cnt = a[i][j]+a[i+1][j]+a[i+1][j+1]+a[i+2][j+1];
  if(maxCount<cnt) maxCount=cnt;
  
  //15
  cnt = a[i][j]+a[i][j+1]+a[i+1][j+1]+a[i+1][j+2];
  if(maxCount<cnt) maxCount=cnt;

  //16
  cnt = a[i][j]+a[i][j+1]+a[i][j+2]+a[i+1][j+1];
  if(maxCount<cnt) maxCount=cnt;
   
  //19
  cnt = a[i][j]+a[i+1][j]+a[i+1][j+1]+a[i+2][j];
  if(maxCount<cnt) maxCount=cnt;

  return maxCount;
}

int type1(int i, int j){
  int maxCount=0;
  int cnt;
  //8
  cnt = a[i][j]+a[i+1][j]+a[i+2][j]+a[i+2][j-1];
  if(maxCount<cnt) maxCount=cnt;

  //13
  cnt = a[i][j]+a[i][j+1]+a[i+1][j]+a[i+1][j-1];
  if(maxCount<cnt) maxCount=cnt;

  //14
  cnt = a[i][j]+a[i+1][j]+a[i+1][j-1]+a[i+2][j-1];
  if(maxCount<cnt) maxCount=cnt;

  //17
  cnt = a[i][j]+a[i+1][j]+a[i+1][j-1]+a[i+2][j];
  if(maxCount<cnt) maxCount=cnt;

  //18
  cnt = a[i][j]+a[i+1][j]+a[i+1][j-1]+a[i+1][j+1];
  if(maxCount<cnt) maxCount=cnt;

  return maxCount;
}

int type2(int i, int j){
  int cnt = a[i][j]+a[i+1][j]+a[i+1][j-1]+a[i+1][j-2];
  return cnt;
}

int main(){
  ios_base::sync_with_stdio(false);
  cin.tie(nullptr);

  for(int i=0; i<=MAX+2; i++){
    for(int j=0; j<=MAX+2; j++){
      // 최솟값을 미리 넣어놓기
      a[i][j]=-5000;
    }
  }

  int n, m;
  cin>>n>>m;
  for(int i=0; i<n; i++){
    for(int j=0; j<m; j++){
      cin>>a[i][j];
    }
  }

  int maxCount=0;
  int cnt;
  for(int i=0; i<n; i++){
    for(int j=0; j<m; j++){
      cnt=type0(i,j);
      if(maxCount<cnt) maxCount=cnt;

      if(j-1>=0){
        cnt=type1(i,j);
        if(maxCount<cnt) maxCount=cnt;
      }

      if(j-2>=0){
        cnt=type2(i,j);
        if(maxCount<cnt) maxCount=cnt;
      }
    }
  }
  cout<<maxCount;
  return 0;
}

 

 

 

 

 

 

'프로그래밍 > PS' 카테고리의 다른 글

[백준 12904] A와 B  (0) 2021.05.28
[백준 2109] 순회강연  (0) 2021.05.26
[백준] 골드V 달성  (0) 2021.03.24
[백준 17404번] RGB거리 2  (0) 2021.03.19
[백준 2133번] 타일채우기  (0) 2021.03.18

mac에서 (`)라는 grave accent를 입력하려고 할 때, (₩)라는 원화 사인이 종종 입력됩니다.

이것때문에 불편하신 분들이 많으실텐데요. 이 현상의 원인은 아래와 같습니다.

mac에서는 한글입력기일 때 ₩, 영어입력기일 때 `가 입력되기 때문입니다.


이것을 해결하기 위해서는 KeyBinding을 설정해주어야 합니다. 다른 포스팅들을 보면 여러가지 과정을 거쳐야 하는 경우가 많은데요,

저는 이것을 아주 간단하게 처리하기 위해서 명령어를 사용해보겠습니다.

terminal 프로그램을 실행한 뒤, 아래의 명령어를 순서대로 입력해주세요.

mkdir ~/Library/KeyBindings
touch ~/Library/KeyBindings/DefaultkeyBinding.dict
open -a "TextEdit" ~/Library/KeyBindings/DefaultkeyBinding.dict

그러면 아래와 같이 TextEditor가 나오는데, 그곳에 아래에 있는 코드를 입력해주시면 됩니다.

{
    "₩" = ("insertText:", "`");
}

입력이 끝나면, 저장한 뒤에 재부팅해주시면 설정이 완료됩니다.

재부팅을 안해도 적용이 되는 경우가 있다고 하는데, 정상적인 작동을 위해서 재부팅을 추천드립니다!

100솔, 골드5 달성기념!

'프로그래밍 > PS' 카테고리의 다른 글

[백준 12904] A와 B  (0) 2021.05.28
[백준 2109] 순회강연  (0) 2021.05.26
[백준 14500] 테트로미노  (0) 2021.03.25
[백준 17404번] RGB거리 2  (0) 2021.03.19
[백준 2133번] 타일채우기  (0) 2021.03.18

필히 개인적인 공부 용도로만 사용하시기 바랍니다.
다른목적으로 영상을 사용했을 경우 법적 책임은 본인에게 있습니다.

이전에 쓴 ted 자막추출과 비슷하게 대학교 강의를 다운받을 수 있습니다.

이 방법을 이용해서 기간이 한정되어있는 동영상 강의들을 다운받아 복습에 사용할 수도 있고,

학교 강의 플랫폼에서는 동영상을 시간대별로 이동하는 기능이 제한되어 있기 때문에
플랫폼에서 강의를 백그라운드로 틀어놓고, 강의를 시간대별로 옮겨가며 편리하게 공부할 수도 있습니다.

방법을 알아봅시다!

준비물은 크롬브라우저, 혹은 파이어폭스 브라우저만 있으면 됩니다.


크롬 기준으로, 맨 오른쪽 점세개->도구 더보기->개발자도구를 클릭합니다.

오른쪽이나 아래쪽에 생성된 개발자도구 화면에서 아래와같은 아이콘을 클릭해줍니다.

여기서 중요한것은 동영상을 한번 실행한 후, 교수님의 강의가 시작되었을 때 선택을 해주어야 한다는 것입니다.

그렇지 않으면 썸네일만 선택되고 동영상은 찾을 수 없을지도 모릅니다.

위의 아이콘을 누르면 영역을 선택할 수 있게 되는데요,

아래와 같이 강의 동영상영역을 선택해줍니다.

선택하게 되면, 다시 개발자도구 화면에서 동영상에 해당하는 코드를 볼 수 있는데요,

코드가 중요한것이 아니고 저 안에있는 src가 우리의 목표입니다.

동영상의 원본 주소를 알아낼 수 있습니다.

더블클릭하면 아래와같이 텍스트를 선택할 수 있는데요,

텍스트에서 마우스 오른쪽을 누른 후, 복사를 선택하면 동영상의 원본 주소를 복사할 수 있습니다.

복사한 주소를 새 탭에 붙여넣으면, 새 탭에서 동영상만 따로 볼 수 있게 됩니다.

이곳에서 강의를 시청한다면 시간대별 찾기기능을 사용할 수 있어서 조금 더 편하게 강의를 들을 수 있게됩니다.

하지만, 대부분이 원하는 것은 동영상파일 저장이기 때문에, 오른쪽 아래의 점세개를 눌러줍니다.

그리고 다운로드를 눌러주게 되면, 동영상 파일을 다운로드 받을 수 있습니다.

이상으로 대학교 동영상 강의를 다운로드 받는 방법에 대해서 알아보았습니다.

학교마다 강의 플랫폼이 다르기 때문에 파일명, 동영상 다운로드버튼 위치등은 다를 수 있지만,
전체적인 개요는 동일하기 때문에 비슷한 방법으로 쉽게 동영상을 다운로드 받을 수 있습니다.

혹시나 본인 학교의 플랫폼에는 적용이 안된다 하시는 분들은 댓글을 남겨주시면 도와드리겠습니다!

+ Recent posts