https://www.jetbrains.com/idea/download/?section=windows
위 링크를 통해 Intellij community edition을 다운받는다. (페이지 아래로 스크롤하면 있어요!) 인터넷에 검색하면 사용법이 많이 알려져 있으니, 이 글에서는 사용법을 생략한다.
Intellij에서 새로운 Java 프로젝트를 만들고 샘플 코드 추가를 활성화한다. 자동으로 Main.java 파일에 있을 것이다.
이제부터 public static void main(String[] args)의 두 중괄호 사이에 코드를 작성할 것이다. 현재 public static void main(String[] args)의 두 중괄호 안에 있는 코드를 지우고, 아래 코드를 입력한다.
System.out.print("Hello, world");
그 후, 상단에 있는 초록색 화살표 버튼을 눌러 코드를 실행한다.
출력:
Hello, world
Java에서는 System.out.print()를 이용해 화면에 글자를 출력한다. 출력하고자 하는 내용을 두 소괄호 사이에 넣으면 된다.
System.out.print()처럼 System.out.println()이 있는데, System.out.print()은 소괄호 안의 값을 출력하고 줄바꿈을 하지 않지만, System.out.println()은 소괄호 안의 값을 출력하고 줄바꿈을 한다.
예를 들어 보겠다.
코드:
public class Main {
public static void main(String[] args) {
System.out.println("Hello world!");
System.out.print("Hello ");
System.out.print("world!");
}
}
출력:
Hello world!
Hello world!
또, 소괄호 안에 사칙연산(+, -, *, /)을 하는 것이 가능하다.
코드:
public class Main {
public static void main(String[] args) {
System.out.print("1 + 1 = ");
System.out.print(1 + 1);
}
}
출력:
1 + 1 = 2
코딩을 하다 보면 정보를 저장해야 하는 경우가 있는데, 그런 정보들을 저장할 수 있는 공간을 변수라고 한다.
변수가 필요하다면, 변수를 선언해야 한다. 아래는 변수를 선언하는 방법이다.
변수타입 변수이름;
이해를 돕기 위해, 실생활에 적용하여 예시를 들어 보겠다. 물건들을 상자들에 저장할 것이다. 효율적으로 물건들을 저장하려면, 큰 물건은 큰 상자, 작은 물건은 작은 상자에 넣어야 한다. 또, 어떤 물건들은 깨지거나 부러질 수 있어, 완충제를 같이 넣어야 한다. 만약 모든 물건들을 상자에 알맞게 넣었다고 해보자. 어떤 상자 안에 무슨 물건이 있는지 모르면 의미가 없어진다. 그렇기 때문에, 내용물의 이름이 적힌 스티커를 붙일 것이다.
Java도 다름없다. 정보가 크고 작은 것에 따라 필요한 저장공간이 다르며, 정보의 형태에 따른 저장이 필요하다. 그렇기 때문에 변수타입이 존재하는 것이다. 내용물이 무엇인지 알 수 있도록, 변수를 선언할때, 변수 이름을 만들어야 하는 것이다.
예를 들어 정수, 영어로 integer여서 정수를 저장하기 위한 변수는 아래처럼 선언한다.
int (변수이름);
만약 변수가 저장하는 값을 바꾸고 싶다면 아래와 같이 하면 된다.
(변수이름) = (바꾸려고 하는 값)
예시 코드:
public class Main {
public static void main(String[] args) {
int x = 5;
System.out.println(x);
x = 3;
System.out.print(x);
}
}
출력:
5
3
예시 코드:
public class Main {
public static void main(String[] args) {
int x = 4;
int y = 2;
System.out.println(x + y);
System.out.println(x - y);
System.out.println(x * y);
System.out.println(x / y);
}
}
출력:
6
2
8
2
가장 많이 사용되는 변수 타입들에 대해 간단히 배워보겠다.
int, long : 정수를 저장하기 위한 타입(20억을 넘을 땐 long 사용)
float, double : 실수(소수)를 저장하기 위한 타입 (float는 오차없이 7자리, double은 15자리)
char : 문자 하나를 저장하기 위한 타입
String : 여러 문자를 저장하기 위한 타입
변수 타입에 따라 정보에 접미사가 붙는 경우가 있다. 아쉽게도 이것은 암기가 필수이다.
long : 접미사가 ‘l’ 혹은 ‘L’
8진수 : 접미사 ‘0’
16진수 : 접미사 ‘0x’ 혹은 ‘0X’
float : 접미사 ‘f’ 혹은 ‘F’
double : 접미사 ‘d’ 혹은 ‘D’
참고 : 상수는 중간에 ‘_‘을 넣어서, 큰 숫자를 읽게 편하게 하는 것이 가능하다.
간단한 예시로 더 이해하기 쉽게 하겠다.
논리형 : false, true (접미사 없음)
참고로 논리형은 아직 배우지 않았으니 참고만 하면 된다.
정수형 : 12, 100L (접미사 L)
실수형 : 3.14, 3.0 (접미사 f, d)
문자형 : ‘a’, ‘A’ (접미사 없음)
문자열 : “AB”, “a” (접미사 없음)
C++ 메인으로 코딩을 하다 보니, 실수를 하는 경우가 많다. 만약 오류 제보를 하고 싶다면 디스코드 아이디 _wha7y_를 통해 제보하시길 바란다.
]]>생각보다 어려운 문제였다. 하지만, 식정리를 하면 깔끔하게 풀리는 문제였다. 대강 2024 NYPC round 2-a을 더 간단화한 버전이라고 보는 것이 가능하다.
1번 문제보다는 직관적이고, 개인적으로 초기화를 제대로 하지 않아 시간이 많이 걸렸다. 그리디와 누적합을 적절히 이용해서 풀면 어렵지 않은 문제였다.
2번 문제가 너무 분별력 없이 쉬워서 대회에세도 은상을 가르는 것이 3번 섭테라고 생각했지만, 3번 문제의 1, 2번 섭태를 수학을 사용해서 O(1)로 풀려고 하였으나, 먹히지 않았다.
223점으로 마무리하여 동상이다. 이번에 3번의 1, 2번 섭태만 긁었어도 은상이였는데 아쉽다. 다음년도 2번이 조금 더 어려워졌으면 좋겠다.
]]>https://www.acmicpc.net/problem/16993
https://www.acmicpc.net/problem/10999
위 문제처럼 문제를 푸는것은 안돼요! 이것은 최대 구간합을 구하지 못해, 오히려 그냥 누적합으로 구간합을 구하는 것이 더 빨라요!
그렇다고 해서 구간합을 누적합을 사용하고 최대값 - 최소값을 하면 최소값이 최대값의 오른쪽에 있을 수 있다는 반례가 있습니다!
그렇다면 이 문제는 어떻게 해결해야 할까요? 이 문제를 해결할 수 있는 테크닉을 금광 세그라고 합니다. 이 문제를 풀려면 마치 이분탐색을 하는 것처럼 풀어야 합니다.
f(i, j) = A[i], A[i+1], …, A[j]에서 가장 큰 연속합 (1 ≤ i ≤ j ≤ N)이라 정의하겠습니다! 히스토그램에서 가장 큰 직사각형을 세그먼트 트리로 풀어보신 분들은 그 문제를 어떻게 풀었는지 다시 한번 생각해 봅시다. 문제를 두 작은 문제로 계속 변환하여 이분탐색처럼 해결했죠? 이 문제도 비슷합니다! 문제를 더 작은 문제 2개로 분활하여 문제를 푸는 것입니다!
mid = (i + j) / 2
f(i, j) = max(f(i, mid), f(mid + 1, j), (두 케이스를 합친 경우))
#include<bits/stdc++.h>
using namespace std;
#define ll long long int
ll n, m;
vector<ll> arr;
typedef struct Node {
ll leftMax, rightMax, _max, psum;
};
vector<Node> tree;
Node Merge(Node left, Node right) {
Node res;
res.leftMax = max(left.leftMax, left.psum + right.leftMax);
res.rightMax = max(right.rightMax, right.psum + left.rightMax);
res._max = max({left._max, right._max, left.rightMax + right.leftMax});
res.psum = left.psum+ right.psum;
return res;
}
void Init(ll start, ll end, ll node) {
if (start == end) {
tree[node].rightMax = arr[start];
tree[node].leftMax = arr[start];
tree[node]._max = arr[start];
tree[node].psum = arr[start];
return;
}
ll mid = (start + end) / 2;
Init(start, mid, node * 2);
Init(mid + 1, end, node * 2 + 1);
tree[node] = Merge(tree[node * 2], tree[node * 2 + 1]);
}
Node Query(ll start, ll end, ll left, ll right, ll node) {
if ((end < left) || (right < start)) {
Node res;
res.rightMax = INT_MIN;
res.leftMax = INT_MIN;
res._max = INT_MIN;
res.psum = INT_MIN;
return res;
}
if ((left <= start) && (end <= right)) {
return tree[node];
}
ll mid = (start + end) / 2;
return Merge(Query(start, mid, left, right, node * 2), Query(mid + 1, end, left, right, node * 2 + 1));
}
int main(void) {
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin >> n;
arr.resize(n);
tree.resize(n * 4);
for (ll i = 0; i < n; i++) {
cin >> arr[i];
}
Init(0, n - 1, 1);
cin >> m;
for (ll i = 0; i < m; i++) {
ll a, b;
cin >> a >> b;
Node res = Query(0, n - 1, a - 1, b - 1, 1);
cout << res._max << "\n";
}
}
만약 1번 풀이 필요하시다면 후기 보시면 됩니다.
나중에 BOJ에 나오면 소스코드 추가하겠습니다.
]]>2교시 1번 문제를 가뿐하게 풀고, 1시간 10 ~ 20분 정도가 남아 있었다. 평소에 구현 연습을 안해서 2번 문제 같은 경우 충분히 풀 수 있을 것 같은데 생각을 정리하지 못해서 그냥 말려버렸다. 또, 3번 문제 같은 경우 문제이해가 전혀 안갔다. 그래서 2교시는 100점으로 마무리했다. 잘봤으면 200점 정도는 되었을것 같은데 아쉽다.
최종 165점으로 마무리해서 본선을 통과하지 못할지도 모른다. 진짜 나는 알고리즘을 파는 것보다 수학을 연습하는게 오히려 좋을 지도 모른다. 작년 초등부에서도 1차보다 2차에서 잘본 것 같다. 워낙 내가 수학 선행을 안하고 이산수학을 싫어하다 보니 이런 것일지도 모른다는 생각이 든다. 진짜 이번에 1교시 좀만 더 집중했으면 은상 가능했을 것 같기도 하고, 현재 상태로 동상이라도 받을 수 있으면 다행일 것 같다.
중등부 2교시 1번문제 풀이 좌표평면 상에 그래프의 기울기는 어떻게 구하는지부터 생각해 보자. 이거는 간단하다.
$(y1 - y2) / (x1 - x2)$로 구할 수 있다. 이 문제에서는 직각삼각형의 빗변이 아닌 변의 기울기가 1 혹은 -1이다. 그러므로 $xi - yi$이 가장 작은 값이랑, $xi + yi$가 가장 큰 값을 구해서 $y$값에 대입해 주고, $xi - yi$이 가장 큰 값이랑, $xi + yi$가 가장 작은 값을 구해서 $y$값에 대입해 주어, 대입해서 나온 두 $ | x1 - x2 | $ 들중에 작은 것을 고르면 된다. |
소스코드:
#include <bits/stdc++.h>
using namespace std;
int main(void) {
int n;
cin >> n;
vector<pair<int, int>> arr(n);
vector<int> r(n);
vector<int> l(n);
int _min = INT_MAX;
int _max = INT_MIN;
for (int i = 0; i < n; i++) {
cin >> arr[i].first >> arr[i].second;
r[i] = arr[i].first + arr[i].second;
l[i] = arr[i].first - arr[i].second;
_min = min(_min, arr[i].second);
_max = max(_max, arr[i].second);
}
sort(r.begin(), r.end());
int a = r[r.size() - 1];
sort(l.begin(), l.end());
int b = l[0];
int x1 = a - _min;
int x2 = b + _min;
int res = abs(x1 - x2);
a = r[0];
b = l[l.size() - 1];
x1 = a - _max;
x2 = b + _max;
res = min(res, abs(x2 - x1));
cout << res;
}
중등부 2교시 2번 배낭문제 스타일의 DP인데, DP배열을 두개로 늘려서 각각 계산하면 되는줄 알았다. 하지만, 두명을 동시에 세는 경우에서 일이 꼬이기 시작한다. 나는 map 사용하고 zral했는데 안풀렸다. 1번 문제는 10분 정도만에 풀었는데, 나머지 시간동안 이 한문제를 못풀었다. 또 이 문제는 적당한 구현 실력이 필요하였지만, 나는 구현을 매우 못한다. 항상 더럽게 코드를 짜는 경향이 있어, 못풀었을지도 모른다.
중등부 2교시 3번 문제 이해부터가 안된다. 무슨 건초의 배치를 어쩌라는 건지 모르겠고, 왜 어떤 경우에서 -1이 나오는지 전혀 이해가 안간다. 내가 문제를 재대로 안읽은 이슈가 제일 크겠지만, 내 국어 이슈가 여기까지 따라오는 것 같다.
앞으로 발전해야 할 것