morenow
morenow
morenow
전체 방문자
오늘
어제
  • 분류 전체보기 (83)
    • 스프링부트와 AWS로 혼자 구현하는 웹 서비스 (5)
    • [MSA] Spring Cloud로 개발하는 마이.. (14)
    • Baekjoon Online Judge (40)
    • Programmers (11)
    • Spring Boot (7)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • re-distribution
  • B Tree
  • Open Feign
  • write skew
  • successHandler
  • 백준20058C++
  • lost update
  • Id Token
  • HTTP Interface
  • HttpExchange
  • B+ Tree
  • jwt
  • Feign Client
  • JWT단점
  • dirty write
  • copy up
  • 백준 파이어스톰
  • Spring Boot
  • 마법사 상어와 파이어스톰
  • Refresh Token Refresh

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
morenow

morenow

Baekjoon Online Judge

[BOJ] 28303: 자석 (C++)

2023. 8. 21. 00:50

https://www.acmicpc.net/problem/28303

 

28303번: 자석

예제 1의 경우 N극이 3번 칸에 놓이고 S극이 5번 칸에 놓이도록 자석을 설치할 때 1번 현상으로 $a_3=22$의 에너지가 충전되며, 2번 현상으로 $a_5=4$의 에너지가 소모되고, 3번 현상으로 $(5-3)\times 2=4$

www.acmicpc.net

걸린 시간 : 49분 11초


UCPC 2023 예선 문제다.

 

문제가 이상한 말을 많이 하지만 돌려돌려 생각해보면 문제 자체는 이해하기 쉽다. a[i] - a[j] - abs(i-j) * K 값을 구하라는 것이다.

 

단순히 생각해 봤을 때, 변수가 i, j 이므로 단순히 탐색을 한다면 O(N^2) 일 것이다. 하지만 N의 범위가 500000이다. 보통 몇천 단위를 넘어가면 의도적으로 O(N^2) 를 막아놓은 것이다. 게다가 이 문제는 대회문제이므로, 수학적인 아이디어가 조금은 필요할 것이라고 생각하고 종이를 꺼내들고 끄적거렸다.

 

"수학적인 아이디어" 라는 생각을 하니 일반항부터 생각났다. 아까 말한 a[i] - a[j] - abs(i-j) * K  를 (a[i] - i * K ) - (a[j] - j * K ) 로 풀어해칠  수 있음이 생각났다. (일단 i > j 인 가정. j > i 인 경우는 다시 또 하면 된다!) 이러면 하나의 일반항으로 생각할 수 있게 된다. 따라서 예제에 나온 배열을 이 일반항을 토대로 배열을 생각해봤다.

해당 배열은 25, 12, 18, 7, -4 이다. i > j 인 경우이므로 이 때 최댓값은 막무가내로 생각해도 6이다. (18-12)

 

중요한 것은, 이걸 O(N^2) 이내에 해야 한다는 것. 정렬이나 이분 탐색같은 아이디어는 없으니 logN 이 끼어들 자리가 없어 아마 O(N) 일 것으로 예상하고 접근해본다.

생각보다 쉽다. i를 증가시키면서 그 전의 최솟값들만 계속 갱신시키면서 계산하면 최댓값이다. 즉, (a[i] - i * K ) - (a[j] - j * K ) 에서 j에 해당하는 값을 최소로 만들면 되니까, 이 값만 최소로 계속 갱신한다는 것이다.

 

그리고 나서, j > i 인 경우는 이 수열을 뒤집어서 생각하면 된다. 항상 이런 문제를 풀 때는 예제 배열을 직접 써보면서 따져가야 실수를 하지 않는다.

 

#include <bits/stdc++.h>
using namespace std;

int N, K, ans = -2100000000;
int a[500001], energe[500001], mn;

int main(void) {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> N >> K;
	for (int i = 0; i < N; i++)
		cin >> a[i];
	//순방향
	for (int i = 0; i < N; i++) {
		energe[i] = a[i] - K * i;
	}
	mn = energe[0];
	for (int i = 1; i < N; i++) {
		ans = max(energe[i] - mn, ans);
		mn = min(mn, energe[i]);
	}
	//역방향
	for (int i = 0; i < N; i++) {
		energe[i] = a[N-i-1] - K * i;
	}
	mn = energe[0];
	for (int i = 1; i < N; i++) {
		ans = max(energe[i] - mn, ans);
		mn = min(mn, energe[i]);
	}
	cout << ans;
	return 0;
}

'Baekjoon Online Judge' 카테고리의 다른 글

[BOJ] 16236: 아기 상어 (C++)  (0) 2023.08.29
[BOJ] 3109: 빵집 (C++)  (0) 2023.08.28
[BOJ] 1780 : 종이의 개수 (C++) with 분할 정복  (0) 2023.08.17
[BOJ] 1874 : 스택 수열 (C++) with 스택  (0) 2023.08.16
[BOJ] 1912: 연속합 (C++) with 누적합  (0) 2023.08.16
    'Baekjoon Online Judge' 카테고리의 다른 글
    • [BOJ] 16236: 아기 상어 (C++)
    • [BOJ] 3109: 빵집 (C++)
    • [BOJ] 1780 : 종이의 개수 (C++) with 분할 정복
    • [BOJ] 1874 : 스택 수열 (C++) with 스택
    morenow
    morenow

    티스토리툴바