'알고리즘 & Problem Solving > 레퍼런스코드' 카테고리의 다른 글
[레퍼런스코드] 유클리드 호제법 최대공약수 구하기(GCD) (2) | 2020.05.15 |
---|---|
[레퍼런스코드] Disjoint Set 코드(DSU / Union-Find 자료구조) (0) | 2020.01.25 |
[레퍼런스코드] 머지소트(병합정렬) (0) | 2019.10.30 |
[레퍼런스코드] 유클리드 호제법 최대공약수 구하기(GCD) (2) | 2020.05.15 |
---|---|
[레퍼런스코드] Disjoint Set 코드(DSU / Union-Find 자료구조) (0) | 2020.01.25 |
[레퍼런스코드] 머지소트(병합정렬) (0) | 2019.10.30 |
작년에 이어서 올해에도 구글 코드잼에 참가했는데, 작년에는 2라운드 진출까지만 하고, 2라운드에서는 그냥 던져버렸었다. 올해에는 좀 더 나아진 모습을 보여주고자 했는데 결국 라운드 1C까지 왔다.
구글 코드잼은 Qualification Round이후 Round 1로 넘어가는데, 1라운드의 경우 A,B,C로 총 3번의 기회가 있다. 각각의 라운드에서 1500등 안에 들면 다음 라운드인 Round 2로 진출하게 되고, A라운드에서 1500등 안에 들어서 다음 라운드로 진출하게 되면 다음 B, C라운드는 참여할 수 없다.
즉 각각 A,B,C 라운드 별 1500명이 다음 라운드로 진출하게 되어 결과적으로는 4500명이 Round 2로 진출하게 된다. 그런데 올해 구글 코드잼의 등록자는 역대급이라고 하며(근데 매년 등록자의 수가 늘어난다고는 한다) 라운드 1A, 1B에서 처참하게 발려버려서 자신감이 꽤나 떨어져있는 상태였다.
대충 처참한 나의 이전 라운드 성적이다.
하지만 이번 라운드에선 아슬아슬하긴 하지만 어째 저째 다음 라운드로 진출하게 될 것 같다.
In review 상태인데, 뭐 부정행위를 한 것도 아니고 1389등을 했으니 Round 2를 체험해볼 수 는 있을 것 같다. 다만 좀 걱정이 되는 것은 Round 2가 DEFCON CTF Qualification Round와 일정이 겹친다는 것... 뭐 코로나 때문에 일정이 더 밀릴수도 있긴 하겠지만 애매한 것은 사실이긴 하다.
어쨋든 기적적으로 라운드 2로 진출하게 되었으니 당분간은, 어차피 이 글을 쓰는 시기로 부터는 열흘밖에 시간이 없긴 하지만 PS 공부를 좀 더 해봐야 겠다.
1번 문제인데, 생각보다 너무 쉽게 나왔어서 오히려 걱정이 되었다. 빨리 풀기 대결이 되지 않을까 하는 그러한 우려이다. 어차피 상대평가라 난이도가 너무 쉬우면 오히려 불리하게 작용할 때도 있었다.
움직이는 녀석을 가장 빨리 만날 수 있는 시간대를 찾는 문제인데, 이동 거리를 L1 Distance(맨하탄 거리)로 바로 알아낼 수 있고, 이동하거나 멈추거나 둘 다 가능하므로, 이동경로별로 원점에서의 맨하탄 거리보다 현재 시간이 더 긴 순간이 만나는 순간이 되겠다.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define endl '\n'
const int dx[] = { +1, -1, 0, 0 };
const int dy[] = { 0, 0, +1, -1 };
int val(char c) {
if (c == 'S') return 3;
if (c == 'N') return 2;
if (c == 'W') return 1;
return 0;
}
void solve() {
int x, y;
string steps;
cin >> x >> y;
cin >> steps;
int ans = -1;
for (size_t i = 0; i < steps.size(); i++) {
int k = val(steps[i]);
x += dx[k];
y += dy[k];
int dist = abs(x) + abs(y);
if (dist <= i + 1) {
ans = i + 1;
break;
}
}
if (ans == -1) {
cout << "IMPOSSIBLE\n";
}
else {
cout << ans << endl;
}
}
int main() {
int tc; cin >> tc;
for (int t = 1; t <= tc; t++) {
printf("Case #%d: ", t);
solve();
}
}
꽤나 신박한 내용의 문제였다. TC가 3가지로 나뉘는데, 마지막 TC의 경우 //(Q=-1//)로 고정이라는 것이 어떻게 보면 힌트가 좀 되었다.
문제 조건을 보면, N, R, D가 각각 chosen independently and uniformly at random from~ 과 같은 제약사항이 있다.
따라서 랜덤의 upper-bound역시 랜덤이므로, 이 값들은 순서는 중구난방이겠지만, 결국은 계단과 같은 모양으로 나타나게 될 것이다. //(10^4//)개의 쿼리 값들을 알려주니 대충 아래와 같은 형식으로의 값들이 나타난다고 볼 수 있겠다.
rand() % 10
rand() % 20
rand() % 30
rand() % 40
...
rand() % 100
이렇게 되면 아무래도 맨 앞자리의 수가 1로 시작하는 수의 값이 맨 앞자리의 수가 2로 시작하는 녀석보다는 많을 것이고, 2로 시작하는 녀석은 3으로 시작하는 녀석보다 많을 것이고.. 와 같은 통계적 상관관계가 나타날 것이다.
이러한 점을 이용해서 가장 앞자리에 나타나는 알파뱃의 출연 빈도를 체크해서 내림차순으로 정렬하면 이 알파뱃들이 1부터 9의 숫자를 나타낼 것이다.
또한 0의 경우는 첫번째 자리에서만 나타날 수 없는 수이므로, 전체 나타난 알파뱃 중 맨 앞자리에 나타나는 알파뱃들을 빼면 나오게 될 것이다.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define endl '\n'
#define NUMTC 10000
typedef pair<ll, string> pis;
typedef pair<ll, char> pic;
ll cnt[30];
void solve() {
set<char> occurs;
set<char> nonzero;
occurs.clear();
nonzero.clear();
memset(cnt, 0, sizeof(cnt));
int U;
pis arr[NUMTC + 5];
vector<pic> ans;
ans.clear();
char output[11];
cin >> U;
for (int i = 0; i < NUMTC; i++) {
cin >> arr[i].first >> arr[i].second;
}
for (int i = 0; i < NUMTC; i++) {
auto& s = arr[i].second;
nonzero.insert(s[0]);
//첫번째만 셈
cnt[s[0] - 'A']++;
for (char c : s) {
occurs.insert(c);
}
}
for (int i = 0; i < 30; i++) {
if (cnt[i]) {
ans.push_back(make_pair(cnt[i], i + 'A'));
}
}
for (auto c : nonzero) {
occurs.erase(c);
}
char zero = *occurs.begin();
sort(ans.begin(), ans.end(), greater<pic>());
for (int i = 0; i < 9; i++) {
output[i+1] = ans[i].second;
}
output[0] = zero;
output[10] = 0;
printf("%s\n", output);
return;
}
int main() {
int tc; cin >> tc;
for (int t = 1; t <= tc; t++) {
printf("Case #%d: ", t);
solve();
}
}
이 문제는 고생을 꽤 했다. 마지막 문제 답게 난이도도 꽤 어려웠던 것 같은 느낌이다.
근데 사실 아이디어는 어느정도 생각을 해서 Middle TC는 맞출 수 있을 것 같았는데 한가지 조건을 빼 먹어서 업솔빙하면서도 많이 틀려먹었다.
결국 wwiiiii님의 코드를 참고한 뒤 힌트를 얻었다.
analysis를 보고 미들 TC를 맞추는 풀이까지만 적용해서 풀어보았다.
조각의 크기를 //(Ai//)중 하나로만 가능하다고 생각한 고정관념에 따라 틀려버렸는데, 조각의 크기는 //(Ai / k//)가 가능하고, 이때 //(k//)는 1과 //(D//)사이의 수가 된다.
analysis에서 Time Complexity가 //(O(D*N^2)//)라고 했을때, D가 왜 들어가나 이해를 못했는데 이것 때문이었다.
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
#define MAXN 305
ll A[MAXN];
void solve() {
ll N, D;
cin >> N >> D;
ll ans = D - 1;
for (int i = 0; i < N; i++) {
cin >> A[i];
}
sort(A, A + N);
// K를 perfect-cut 개수라고 하면 D - K가 정답이 된다.
for (int i = 0; i < N; i++) {
for (ll k = 1; k <= D; k++) {
ll unit = A[i];// 조각의 크기는 unit / k이다.
ll pieces = 0; //조각의 개수
for (int j = 0; j < N; j++) {
ll chunk = A[j];
pieces += chunk * k / unit;
}
if (pieces < D) continue; //다 잘라도 이 조각 개수가 안나오는 경우 skip
pieces = 0;
int K = 0; // 모두 다 떨어지는 조각 개수
for (int j = 0; j < N; j++) {
ll chunk = A[j];
ll add = chunk * k / unit;
if ((chunk * k) % unit == 0 && pieces + add <= D) {
pieces += add;
K++;
}
}
ans = min(ans, D - K);
}
}
cout << ans << endl;
}
int main() {
int tc; cin >> tc;
for (int t = 1; t <= tc; t++) {
printf("Case #%d: ", t);
solve();
}
}
TC 3에 대한 솔루션 코드 업솔빙은 나중에 시간나면 해보도록 하겠다..... 나중에 스코어 보드를 보니, 한국인 참가자 중에서는 TC3를 맞춘 사람이 1명도 없었다. 코드를 보니 아이디어는 대충 비슷하게 구현은 한 것 같은데 다들 TLE가 나서 그런듯 하다.
TC3에 대한 심플한 솔루션 코드를 odh님이 작성하셨다. 참고해보면 좋을듯.
이진 탐색, 이분 탐색(binary search) 구현시 고려할 것들 (0) | 2020.10.04 |
---|---|
[책 리뷰] 이것이 취업을 위한 코딩테스트다 with 파이썬(by 나동빈) (0) | 2020.08.07 |
Google Codejam Kickstart 2020 Round B 후기 (0) | 2020.04.22 |
Google Codejam 2020 Qualification Round 후기 (0) | 2020.04.05 |
Google Kickstart Round A 2020 풀어보기 (0) | 2020.03.31 |
https://www.acmicpc.net/problem/1620
1620번: 나는야 포켓몬 마스터 이다솜
첫째 줄에는 도감에 수록되어 있는 포켓몬의 개수 N이랑 내가 맞춰야 하는 문제의 개수 M이 주어져. N과 M은 1보다 크거나 같고, 100,000보다 작거나 같은 자연수인데, 자연수가 뭔지는 알지? 모르면 물어봐도 괜찮아. 나는 언제든지 질문에 답해줄 준비가 되어있어. 둘째 줄부터 N개의 줄에 포켓몬의 번호가 1번인 포켓몬부터 N번에 해당하는 포켓몬까지 한 줄에 하나씩 입력으로 들어와. 포켓몬의 이름은 모두 영어로만 이루어져있고, 또, 음... 첫 글자만
www.acmicpc.net
Rust언어를 공부하면서 책을 보고 예제를 보고는 있는데 그래도 코드를 좀 짜봐야지 익숙해질 것 같은 느낌이 든다. 그래서 백준 문제중에서 만만한 것들을 Rust로 좀 풀어보기로 하였다.
일단 만만한 문제의 기준은 https://solved.ac/class/에 있는 녀석 중 내가 아직 안 푼 문제들이다.
일단근데 Rust는 Input 받는것 부터 잘 몰라서, 다음 깃허브에 있는 녀석들을 한번 참고하면 좋을 듯 하다.
https://github.com/EbTech/rust-algorithms
EbTech/rust-algorithms
Common data structures and algorithms in Rust. Contribute to EbTech/rust-algorithms development by creating an account on GitHub.
github.com
깃허브 자체가 Rust로 Contest나가는거니... scanner도 보인다.
문제 자체는 간단하다, String 배열로 받아서 저장해놓고 그때그때 맞는 녀석 출력하면 될 듯 하다. 한번 Rust로 짜보자..!
#![allow(unused_imports)]
#![allow(dead_code)]
use std::cmp::*;
use std::collections::*;
struct Scanner {
buffer : std::collections::VecDeque<String>
}
impl Scanner {
fn new() -> Scanner {
Scanner {
buffer: std::collections::VecDeque::new()
}
}
fn next<T : std::str::FromStr >(&mut self) -> T {
if self.buffer.len() == 0 {
let mut input = String::new();
std::io::stdin().read_line(&mut input).ok();
for word in input.split_whitespace() {
self.buffer.push_back(word.to_string())
}
}
let front = self.buffer.pop_front().unwrap();
front.parse::<T>().ok().unwrap()
}
fn next_str(&mut self) -> String {
if self.buffer.len() == 0 {
let mut input = String::new();
std::io::stdin().read_line(&mut input).ok();
for word in input.split_whitespace() {
self.buffer.push_back(word.to_string())
}
}
self.buffer.pop_front().unwrap()
}
}
fn main() {
let mut cin = Scanner::new();
let n:usize = cin.next();
let m:usize = cin.next();
let mut arr = vec![]; // index to string
let mut hash = HashMap::new(); // string to index
for i in 0..n {
let name = cin.next_str();
arr.insert(i, name.clone());
hash.insert(name.clone(), i);
}
for _ in 0..m {
let query = cin.next_str();
if query.parse::<i32>().is_ok() {
let index: usize = query.parse::<usize>().unwrap();
println!("{}", arr[index-1]);
} else {
match hash.get(&query) {
Some(index) => println!("{}", index+1),
None => println!("Error case!")
}
}
}
}
어째 저째 대충 짜본 코드이다.
스캐너로 input 받는것은 아래 레퍼런스를 참고했다.
http://codeforces.com/contest/702/submission/19589375
Submission #19589375 - Codeforces
codeforces.com
정답은 나올거같은데, TLE가 난다. 왜그런진 모르겟음
그래서 답답한 마음에 C++로 후다닥 다시 짜서 보았다.
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define MAXN 100005
string arr[MAXN];
map<string, int> mm;
int main() {
int n, m;
cin >> n >> m;
ios::sync_with_stdio(false);
cin.tie(NULL);
for(int i=1 ;i <= n; i++) {
string s;
cin >> s;
arr[i] = s;
mm[s] = i;
}
for (int i=0; i < m; i++) {
string v;
cin >> v;
if (v[0] >= 'A') {
cout << mm[v] << endl;
} else {
int idx = atoi(v.c_str());
cout << arr[idx] << endl;
}
}
}
하 C++로 하면 이렇게 간단하게 코드를 짤 수 있는데... 근데 보니깐 sync_with_stdio(false)를 넣지 않으면 TLE가 나는걸로 봐서는 아마 러스트 코드에서 TLE가 나는것은 Scanner가 느리거나, 인풋 받는데 vector를 선언해서 받고 하는데 이런게 느려서 그런거지 않을까 싶다.
고로... PS는 C++이 참 편하긴 한듯.
Rust로 웹 서버를 만들어 보자 (0) | 2020.07.28 |
---|---|
[Rust로 PS하기] 백준 2748번 피보나치 수 2번 풀이 (0) | 2020.05.10 |