no image
[백준-23296] 엘리베이터 조작
2021 APC (아주대학교 프로그래밍) 대회 문제중 하나였다. 예전에 엘리베이터 관련 문제를 카카오 2차 기출에서 본 듯해서 그걸로 푸는건가? 했지만 해당 문제는 단지 dfs 탐색을 통해 일일이 체킹만 해주면 되는 문제이다. 다만 한가지 집고 넘어가야할 점이 있다. dfs 로 일일이 순회를 해주다가 해당 층에 사람이 없는 경우가 생기게 된다. 이렇게 되면 사람이 있는 층들 중에 한 곳으로 가야하는데 어떤 기준으로 갈 곳을 정해줄까? 에 대한 문제이다. 위상정렬 알고리즘에서 힌트를 가져왔다. 각 층을 원하는 사람의 수를 배열 하나 두어서 체킹해준 다음에 원하는 사람이 작은 층을 갈 곳으로 정하면 된다. 이렇게 되면 중간에 건너띄는 층 없이 모든 층을 깔끔하게 순회할 수 있기 때문이다. 이 점때문에 골드 ..
2021.11.07
no image
[백준-23295] 스터디 시간 정하기 1
해당 문제는 아주대 프로그래밍 경시대회 div 1 문제 였다. 대회 때 문제를 보자마자 누적합이라는 걸 캐치한 뒤 빠르게 푼 기억이 있다. 일단 문제를 푸는 로직은 다음과 같다. 입력받는 스터디 시간들을 +1 -1 prefix 로직을 통해 체킹을 해준다. 체킹을 모두 완료한 뒤에 각각 시간대의 사람 수를 계산하고, 그 계산한 값으로 누적합 배열을 초기화해준다. 위 과정을 통해 누적합 배열을 초기화해주었다면 그 다음에는 m 만큼의 슬라이딩 윈도우를 만들어 O(N)의 복잡도로 가장 많은 사람들이 있는 시간 구역을 찾으면 끝이다. #include #include using namespace std; typedef long long LL; LL arr[200000]; LL cnt[200000]; LL sum[2..
2021.11.05
no image
[백준-1939] 중량제한
간단한 BFS + 이분탐색 문제였다. 일단 입력 값을 보았을 때, node 의 개수가 10000개에 다리의 개수가 10만개이다. 때문에 전체를 다 탐색하게 되면 시간 초과가 발생할 수 있다. 때문에 다음과 같은 로직으로 푸는게 안전하다. 최소, 최대 cost 값을 찾은 다음에 이분탐색으로 적절한 cost 값을 찾는다. 각 cost 값 마다 bfs 를 통해 start - finish 경로가 있는지 확인한다. #include #include #include #include #include #include using namespace std; typedef pair pii; typedef long long ll; int check[100001]; int start, finished; vector v[10000..
2021.10.21
no image
[백준-17135] 캐슬디팬스
시뮬레이션 + 백트래킹 문제이다. 1차적으로 궁수 3명을 N+1 번째 행에 3명을 조합의 경우의 수로 세워둔다. 그 다음 2차적으로 시간을 N까지 증가시키면서 적들을 아래 칸으로 한칸씩 움직이도록 한다. 3차적으로 한 칸씩 움직인 적들 중 각 궁수에게 가장 가까운, 거리가 같다면 제일 왼쪽에 있는 놈을 찾는 O(NlogN) 로직을 짜준다. 그 후 하나하나 죽이면서 죽는 놈들을 세어주면 된다. #define _CRT_SECURE_NO_WARNINGS #include #include #include #include #include #include #include #include #define MAX_NUM 1000000009 using namespace std; typedef long long LL; typ..
2021.10.03
no image
[백준-3020] 개똥벌레
해당 높이에 몇개의 장애물이 있는지 누적합을 사용하는 문제이다. +-prefix 를 사용하여 어디서부터 어디까지 +인지 체크해주면 간단하게 누적합을 구할 수 있으며, O(N)의 복잡도로 문제를 풀 수 있다. #define _CRT_SECURE_NO_WARNINGS #include #include #include #include #include #include #include #include using namespace std; typedef long long LL; int sum[500001]; int main() { int n, m, a, b, c; scanf("%d %d", &n, &m); for (int i = 1; i
2021.10.01
no image
[백준-14391] 종이조각
백트래킹 문제이다. 일단 2차원 위치를 하나의 num으로 두고 나머지와, 몫으로 좌표를 설정하도록 한다. 그 후 하나씩 돌아가면서 해당 수만 직사각형 종이에 포함할 것인가 해당 수의 아래를 직사각형 종이에 포함할 것인가 해당 수의 오른쪽을 직사각형 종이에 포함할 것인가 를 하나씩 처리해주면서 문제를 풀면 간단하다. #define _CRT_SECURE_NO_WARNINGS #include #include #include #include #include #include #include #include using namespace std; // 입력값이 100만 -> nlogn 으로 끝내야 한다. int arr[5][5]; int check[5][5]; int dx[] = { -1, 0 }; int dy[] ..
2021.10.01
no image
[백준-19951] 태상이의훈련소생활
+-누적합 문제이다. 값의 변경을 일일이 배열에 체킹해주면 터지게 된다. 때문에 이를 +-누적합을 통해 구해줄 수 있다. ground : 첫 값이 들어가있는 배열 arr : "+ -" 체킹 배열 sum : 최종적으로 몇 만큼 변경해야하는지 들어있는 배열 #include using namespace std; typedef long long LL; int sum[100001]; int arr[100002]; int ground[100002]; int main() { int n, m, a, b, c; scanf("%d %d", &n, &m); for (int i = 1; i
2021.09.30
no image
[백준-10800] 컬러볼
20만의 입력값에 대응하기 위해 nlogn 또는 n의 복잡도로 문제를 풀어야 한다. 이를 위해 누적합을 통해 문제를 풀 수 있다. 다만 전체 합에 대한 누적합과 각 색상에 대한 누적합을 따로 구하여 해당 값을 처리해주면 된다. 이를 2가지 방법으로 구현하였다. 각 색상에 대한 누적합을 구해놓고, 각각의 답을 구할 시에 이분탐색을 돌린다. 모든 명령어를 정렬한 뒤 색에 대한 누적합과 전체에 대한 누적합을 동시에 진행해준다. #define _CRT_SECURE_NO_WARNINGS #include #include #include #include using namespace std; typedef long long LL; typedef pair pii; LL input; LL arr[2001]; LL all_..
2021.09.30
no image
[백준-10986] 나머지 합
누적합과 조합 계산식이 필요한 문제다. 일단 입력값을 보면 100만임을 봐서 최소 O(NlogN) 의 복잡도 내로 끝내야 함을 알 수 있다. 허나 이 문제의 경우 각 누적합을 통해 O(N) 복잡도로 끝낼 수 있다. 로직은 다음과 같다. 입력되는 배열을 순서대로 sum 배열에 넣되 m으로 나눈 나머지 값을 쭉 넣어준다. sum 배열을 순회하면서 원소를 pai 배열에 체킹해준다. pai 배열에 체킹된 순서로 순회하면서 조합식을 더하면 답이 된다. 이렇게 pai 배열을 둔 이유는 sum[i] - sum[j] = 0 이 되는 경우의 수를 찾아야 하는데 결국 sum[i] == sum[j] 인 경우를 찾는 것과 다름이 없다. 따라서 같은 값을 가지는 sum 배열의 원소들을 쭉 체킹해준 다음 nC2의 조합식에 따라 ..
2021.09.29

2021 APC (아주대학교 프로그래밍) 대회 문제중 하나였다.

예전에 엘리베이터 관련 문제를 카카오 2차 기출에서 본 듯해서 그걸로 푸는건가? 했지만 해당 문제는 단지 dfs 탐색을 통해 일일이 체킹만 해주면 되는 문제이다.

다만 한가지 집고 넘어가야할 점이 있다. dfs 로 일일이 순회를 해주다가 해당 층에 사람이 없는 경우가 생기게 된다. 이렇게 되면 사람이 있는 층들 중에 한 곳으로 가야하는데 어떤 기준으로 갈 곳을 정해줄까? 에 대한 문제이다.

위상정렬 알고리즘에서 힌트를 가져왔다. 각 층을 원하는 사람의 수를 배열 하나 두어서 체킹해준 다음에 원하는 사람이 작은 층을 갈 곳으로 정하면 된다. 이렇게 되면 중간에 건너띄는 층 없이 모든 층을 깔끔하게 순회할 수 있기 때문이다. 이 점때문에 골드 2로 책정되지 않았나 생각이 든다.

#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>

using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
int arr[200000]; // 각 층을 원하는 사람의 수
int check[100002];

struct compare {
    bool operator()(pii a, pii b) {
        if (a.first == b.first)
            return a.second > b.second;
        return a.first > b.first;
    }
};
vector<vector<int>> v;
priority_queue<pii, vector<pii>, compare> pq;
void dfs(int x, vector<int> &buf) {
    if (check[x]) {
        return;
    }
    check[x] = 1;
    for (int i = 0; i < v[x].size(); i++) {
        buf.push_back(v[x][i]);
        dfs(v[x][i], buf);
    }
}
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);
    
    int n, input;
    cin >> n;
    v = vector<vector<int>>(n + 1);
    for (int i = 1; i <= n; i++) {
        cin >> input;
        v[i].push_back(input);
        arr[input] += 1;
    }

    vector<int> tp;
    dfs(1, tp);
    for (int i = 1; i <= n; i++) 
        pq.push({ arr[i], i });
    

    while (!pq.empty()) {
        int cval = pq.top().first;
        int cidx = pq.top().second;
        pq.pop();

        if (check[cidx]) continue;
        tp.push_back(cidx);
        dfs(cidx, tp);
    }

    cout << tp.size() << endl;
    for (int i = 0; i < tp.size(); i++) {
        cout << tp[i] << " ";
    }
}

 

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

 

23296번: 엘리베이터 조작

예제 1의 경우 1층에서 사람을 태워 4층으로 이동시켜 내려주고, 4층에서 사람을 태워 5층으로 이동시켜 내려주고, 5층에서 사람을 태워 2층으로 이동시켜 내려주고, 2층에서 사람을 태워 4층으로

www.acmicpc.net

 

'책장 > 알고리즘' 카테고리의 다른 글

[백준-23295] 스터디 시간 정하기 1  (0) 2021.11.05
[백준-1939] 중량제한  (0) 2021.10.21
[백준-17135] 캐슬디팬스  (0) 2021.10.03
[백준-3020] 개똥벌레  (0) 2021.10.01

해당 문제는 아주대 프로그래밍 경시대회 div 1 문제 였다.

대회 때 문제를 보자마자 누적합이라는 걸 캐치한 뒤 빠르게 푼 기억이 있다.

일단 문제를 푸는 로직은 다음과 같다. 입력받는 스터디 시간들을 +1 -1 prefix 로직을 통해 체킹을 해준다. 체킹을 모두 완료한 뒤에 각각 시간대의 사람 수를 계산하고, 그 계산한 값으로 누적합 배열을 초기화해준다.

위 과정을 통해 누적합 배열을 초기화해주었다면 그 다음에는 m 만큼의 슬라이딩 윈도우를 만들어 O(N)의 복잡도로 가장 많은 사람들이 있는 시간 구역을 찾으면 끝이다.

#include <iostream>
#include <algorithm>

using namespace std;
typedef long long LL;
LL arr[200000];
LL cnt[200000];
LL sum[200000];

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int n, m;
    cin >> n >> m;

    LL tc, fr, to, max_time = 0;
    for (int i = 0; i < n; i++) {
        cin >> tc;
        for (int j = 0; j < tc; j++) {
            cin >> fr >> to;
            arr[fr] += 1;
            arr[to] -= 1;
            max_time = max(max_time, to);
        }
    }
    cnt[0] = arr[0];
    sum[0] = arr[0];
    for (int i = 1; i <= max_time; i++) {
        cnt[i] = cnt[i - 1] + arr[i];
        sum[i] = sum[i - 1] + cnt[i];
    }

    LL max_cnt = 0, clo = 0;
    for (LL lo = 0; lo <= max_time; lo++) {
        LL calc;
        if (lo == 0) {
            calc = sum[lo + m] - cnt[lo + m];
        }
        else {
            calc = sum[lo + m] - sum[lo - 1] - cnt[lo+m];
        }
        if (calc > max_cnt) {
            max_cnt = calc;
            clo = lo;
        }
    }
    cout << clo << " " << clo + m;
}
 

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

 

23295번: 스터디 시간 정하기 1

첫째 줄에는 스터디에 참가하고자하는 참가자 수 N과 스터디 시간 T가 주어진다. (1 ≤ N ≤ 100,000, 1 ≤ T ≤ 100,000) 다음 줄부터 참가하고자 하는 참가자들의 시간 정보가 N개 주어진다. 각 정보의

www.acmicpc.net

 

'책장 > 알고리즘' 카테고리의 다른 글

[백준-23296] 엘리베이터 조작  (0) 2021.11.07
[백준-1939] 중량제한  (0) 2021.10.21
[백준-17135] 캐슬디팬스  (0) 2021.10.03
[백준-3020] 개똥벌레  (0) 2021.10.01

간단한 BFS + 이분탐색 문제였다.

일단 입력 값을 보았을 때, node 의 개수가 10000개에 다리의 개수가 10만개이다. 때문에 전체를 다 탐색하게 되면 시간 초과가 발생할 수 있다. 때문에 다음과 같은 로직으로 푸는게 안전하다.

  • 최소, 최대 cost 값을 찾은 다음에 이분탐색으로 적절한 cost 값을 찾는다.
  • 각 cost 값 마다 bfs 를 통해 start - finish 경로가 있는지 확인한다.
#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
#include <queue>
#include <string.h>

using namespace std;
typedef pair<int,int> pii;
typedef long long ll;

int check[100001];
int start, finished;
vector<pii> v[100001];

bool bfs(int cost) {
	queue<int> q;
	q.push(start);
	check[start] = 1;
	
	while(!q.empty()) {
		int cx = q.front();
		q.pop();
		
		if(cx == finished) {
			return true;
		}
		
		for(int i=0 ; i<v[cx].size() ; i++) {
			int tx = v[cx][i].first;
			int tval = v[cx][i].second;
			if(check[tx]) continue;
			if(cost > tval) continue;
			
			check[tx] = 1;
			q.push(tx);
		}
	}
	return false;
}

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(NULL), cout.tie(NULL);
	
	int n, m;
	int a, b, c, cmax = 0;
	cin >> n >> m;
	
	
	for(int i=1 ; i<=m ; i++) {
		cin >> a >> b >> c;
		v[a].push_back({b, c});
		v[b].push_back({a, c});
		cmax = max(cmax, c);
	}

	cin >> start >> finished;
	int left = 0, right = cmax, mid;
	int nmax = 0;
	while(left <= right) {
		
		mid = (left + right) / 2;
		memset(check, 0, sizeof(check));
		if(bfs(mid)) {
			left = mid + 1;
			nmax = max(nmax, mid);
		}
		else {
			right = mid - 1;
		}
	}
	cout << nmax;
}
 

1939번: 중량제한

첫째 줄에 N, M(1 ≤ M ≤ 100,000)이 주어진다. 다음 M개의 줄에는 다리에 대한 정보를 나타내는 세 정수 A, B(1 ≤ A, B ≤ N), C(1 ≤ C ≤ 1,000,000,000)가 주어진다. 이는 A번 섬과 B번 섬 사이에 중량제한이

www.acmicpc.net

 

'책장 > 알고리즘' 카테고리의 다른 글

[백준-23296] 엘리베이터 조작  (0) 2021.11.07
[백준-23295] 스터디 시간 정하기 1  (0) 2021.11.05
[백준-17135] 캐슬디팬스  (0) 2021.10.03
[백준-3020] 개똥벌레  (0) 2021.10.01

시뮬레이션 + 백트래킹 문제이다.

1차적으로 궁수 3명을 N+1 번째 행에 3명을 조합의 경우의 수로 세워둔다. 그 다음 2차적으로 시간을 N까지 증가시키면서 적들을 아래 칸으로 한칸씩 움직이도록 한다. 3차적으로 한 칸씩 움직인 적들 중 각 궁수에게 가장 가까운, 거리가 같다면 제일 왼쪽에 있는 놈을 찾는 O(NlogN) 로직을 짜준다. 그 후 하나하나 죽이면서 죽는 놈들을 세어주면 된다.

 

#define _CRT_SECURE_NO_WARNINGS

#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <string.h>
#include <math.h>

#define MAX_NUM 1000000009
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
int n, m, d;
int arr[17][17];
int check[16][16];
int dx[] = { -1,0,1,0 };
int dy[] = { 0,-1,0,1 };
vector<pii> am;
int maxn = 0;
pii arc_pos;
int cur_time;

bool compare(pii a, pii b) {
	int ta = abs(a.first + cur_time - arc_pos.first) + abs(a.second - arc_pos.second);
	int tb = abs(b.first + cur_time - arc_pos.first) + abs(b.second - arc_pos.second);
	if (ta == tb) {
		return a.second < b.second;
	}
	else {
		return ta < tb;
	}
}
int getAnmy(vector<pii> &arc) {
	int res = 0;
	int am_check[17][17] = { 0, };
	int checked[17][17] = { 0, };
	// 시간 [0, n)
	for (int t = 0; t < n; t++) {
		vector<pii> shoted;
		// 적 위치 -> 각 궁수들은 자신과 가장 가까운 놈을 찾아야함
		for (int j = 0; j < arc.size(); j++) {
			int ax = arc[j].first;
			int ay = arc[j].second;
			arc_pos = { ax, ay };
			cur_time = t;
			sort(am.begin(), am.end(), compare);

			for (auto pos : am) {
				int sx = pos.first;
				int sy = pos.second;
				if (sx + t > n) continue;
				if (abs(sx + t - ax) + abs(sy - ay) > d) break;
				if (checked[sx][sy]) continue;
				if (am_check[sx][sy] == 0)
					shoted.push_back({ sx, sy });
				am_check[sx][sy] = 1;
				break;
			}
		}

		for (int j = 0; j < shoted.size(); j++) {
			int tx = shoted[j].first;
			int ty = shoted[j].second;
			checked[tx][ty] = 1;
			res += 1;
		}
	}
	return res;
}
void bt(int num, int cnt, vector<pii> &arc) {
	int x = n+1, y = num;

	if (cnt == 3) {
		int res = getAnmy(arc);
		maxn = max(res, maxn);
		return;
	}
	if (num > m) return;

	arc.push_back({ x, y });
	bt(num + 1, cnt + 1, arc);
	arc.pop_back();
	bt(num + 1, cnt, arc);
}

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

	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			scanf("%d", &arr[i][j]);
			if (arr[i][j]) 
				am.push_back({ i,j });
		}
	}
	vector<pii> arc;
	bt(1, 0, arc);
	printf("%d\n", maxn);
	return 0;
}
 

17135번: 캐슬 디펜스

첫째 줄에 격자판 행의 수 N, 열의 수 M, 궁수의 공격 거리 제한 D가 주어진다. 둘째 줄부터 N개의 줄에는 격자판의 상태가 주어진다. 0은 빈 칸, 1은 적이 있는 칸이다.

www.acmicpc.net

 

'책장 > 알고리즘' 카테고리의 다른 글

[백준-23295] 스터디 시간 정하기 1  (0) 2021.11.05
[백준-1939] 중량제한  (0) 2021.10.21
[백준-3020] 개똥벌레  (0) 2021.10.01
[백준-14391] 종이조각  (0) 2021.10.01

해당 높이에 몇개의 장애물이 있는지 누적합을 사용하는 문제이다.

+-prefix 를 사용하여 어디서부터 어디까지 +인지 체크해주면 간단하게 누적합을 구할 수 있으며, O(N)의 복잡도로 문제를 풀 수 있다.

#define _CRT_SECURE_NO_WARNINGS

#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <string.h>
#include <math.h>
using namespace std;
typedef long long LL;

int sum[500001];
int main() {
	int n, m, a, b, c;
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &a);
		if (i % 2 == 0) {
			sum[m - a + 1] += 1;
		}
		else if (i % 2 != 0) {
			sum[a + 1] -= 1;
			sum[1] += 1;
		}
	}
	vector<int> ans = { 0 };
	for (int i = 1; i <= m; i++) {
		ans.push_back(ans.back() + sum[i]);
	}
	int minn = 200001;
	int mincnt = 0;
	for (int i = 1; i < ans.size(); i++) {
		if (minn > ans[i]) {
			mincnt = 1;
			minn = ans[i];
		}
		else if (minn == ans[i]) {
			mincnt += 1;
		}
	}
	printf("%d %d", minn, mincnt);
	return 0;
}
 

3020번: 개똥벌레

개똥벌레 한 마리가 장애물(석순과 종유석)로 가득찬 동굴에 들어갔다. 동굴의 길이는 N미터이고, 높이는 H미터이다. (N은 짝수) 첫 번째 장애물은 항상 석순이고, 그 다음에는 종유석과 석순이

www.acmicpc.net

 

'책장 > 알고리즘' 카테고리의 다른 글

[백준-1939] 중량제한  (0) 2021.10.21
[백준-17135] 캐슬디팬스  (0) 2021.10.03
[백준-14391] 종이조각  (0) 2021.10.01
[백준-19951] 태상이의훈련소생활  (0) 2021.09.30

백트래킹 문제이다. 일단 2차원 위치를 하나의 num으로 두고 나머지와, 몫으로 좌표를 설정하도록 한다. 그 후 하나씩 돌아가면서

  • 해당 수만 직사각형 종이에 포함할 것인가
  • 해당 수의 아래를 직사각형 종이에 포함할 것인가
  • 해당 수의 오른쪽을 직사각형 종이에 포함할 것인가

를 하나씩 처리해주면서 문제를 풀면 간단하다.

#define _CRT_SECURE_NO_WARNINGS

#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <string.h>
#include <math.h>

using namespace std;
// 입력값이 100만 -> nlogn 으로 끝내야 한다.

int arr[5][5];
int check[5][5];
int dx[] = { -1, 0 };
int dy[] = { 0, -1 };
int n, m;

int setCheck(int x, int y, int mode, int r, int num) {
	vector<int> ans;
	if (mode == 1) {
		for (int i = x; i <= x + r; i++) {
			if (check[i][y] && num == 1) return -1;
		}
		for (int i = x; i <= x + r; i++) {
			check[i][y] = num;
			ans.push_back(arr[i][y]);
		}
	}
	else {
		for (int i = y; i <= y + r; i++) {
			if(check[x][i] && num == 1) return -1;
		}
		for (int i = y; i <= y + r; i++) {
			check[x][i] = num;
			ans.push_back(arr[x][i]);
		}
	}
	int res = 0;
	for (int i = 0; i < ans.size(); i++) {
		res *= 10;
		res += ans[i];
	}
	return res;
}
int maxn = 0;

void bf(int num, int sum) {
	if (num > n * m) {
		maxn = max(sum, maxn);
		return;
	}
	int x, y;
	if (num % n == 0) {
		x = n;
		y = num / n;
	}
	else {
		x = num % n;
		y = num / n + 1;
	}
	
	if (check[x][y] == 1) {
		bf(num + 1, sum);
	}
	else if (check[x][y] == 0) {
		// 해당 원소만
		check[x][y] = 1;
		bf(num + 1, sum + arr[x][y]);
		check[x][y] = 0;

		// 아래 원소 포함
		for (int k = 1; k <= n - x; k++) {
			int tp = setCheck(x, y, 1, k, 1);
			if (tp == -1) continue;
			bf(num + 1, sum + tp);
			setCheck(x, y, 1, k, 0);
		}

		// 오른쪽 원소 포함
		for (int k = 1; k <= m - y; k++) {
			int tp = setCheck(x, y, 2, k, 1);
			if (tp == -1) continue;
			bf(num + 1, sum + tp);
			setCheck(x, y, 2, k, 0);
		}
	}
	maxn = max(sum, maxn);
}
int main() {
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			scanf(" %1d", &arr[i][j]);
		}
	}
	bf(1, 0);
	printf("%d\n", maxn);
	return 0;
}

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

 

14391번: 종이 조각

영선이는 숫자가 쓰여 있는 직사각형 종이를 가지고 있다. 종이는 1×1 크기의 정사각형 칸으로 나누어져 있고, 숫자는 각 칸에 하나씩 쓰여 있다. 행은 위에서부터 아래까지 번호가 매겨져 있고,

www.acmicpc.net

 

'책장 > 알고리즘' 카테고리의 다른 글

[백준-17135] 캐슬디팬스  (0) 2021.10.03
[백준-3020] 개똥벌레  (0) 2021.10.01
[백준-19951] 태상이의훈련소생활  (0) 2021.09.30
[백준-10800] 컬러볼  (0) 2021.09.30

+-누적합 문제이다.

값의 변경을 일일이 배열에 체킹해주면 터지게 된다. 때문에 이를 +-누적합을 통해 구해줄 수 있다.

  • ground : 첫 값이 들어가있는 배열
  • arr : "+ -" 체킹 배열
  • sum : 최종적으로 몇 만큼 변경해야하는지 들어있는 배열
#include <cstdio>

using namespace std;
typedef long long LL;

int sum[100001];
int arr[100002];
int ground[100002];

int main() {
	int n, m, a, b, c;
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &ground[i]);
	}

	for (int i = 0; i < m; i++) {
		scanf("%d %d %d", &a, &b, &c);
		arr[a] += c;
		arr[b + 1] -= c;
	}

	for (int i = 1; i <= n; i++) 
		sum[i] = sum[i - 1] + arr[i];
	
	for (int i = 1; i <= n; i++) {
		ground[i] += sum[i];
		printf("%d ", ground[i]);
	}
	return 0;
}
 

19951번: 태상이의 훈련소 생활

2020년 5월 14일 논산훈련소에 입대한 태상이는 첫 총기 훈련에서 가스 조절기를 잃어버리는 중대한 실수를 범했다. 그로 인해, 태상이는 조교들에게 눈총을 받게 되었다. 조교들은 태상이에게 연

www.acmicpc.net

 

'책장 > 알고리즘' 카테고리의 다른 글

[백준-3020] 개똥벌레  (0) 2021.10.01
[백준-14391] 종이조각  (0) 2021.10.01
[백준-10800] 컬러볼  (0) 2021.09.30
[백준-10986] 나머지 합  (0) 2021.09.29

20만의 입력값에 대응하기 위해 nlogn 또는 n의 복잡도로 문제를 풀어야 한다.

이를 위해 누적합을 통해 문제를 풀 수 있다. 다만 전체 합에 대한 누적합과 각 색상에 대한 누적합을 따로 구하여 해당 값을 처리해주면 된다. 이를 2가지 방법으로 구현하였다.

  1. 각 색상에 대한 누적합을 구해놓고, 각각의 답을 구할 시에 이분탐색을 돌린다.
  2. 모든 명령어를 정렬한 뒤 색에 대한 누적합과 전체에 대한 누적합을 동시에 진행해준다.
#define _CRT_SECURE_NO_WARNINGS

#include <vector>
#include <algorithm>
#include <cstdio>
#include <queue>

using namespace std;
typedef long long LL;
typedef pair<int, int> pii;

LL input;
LL arr[2001];
LL all_sum[2001];
vector<vector<LL>> v(200001);
vector<vector<LL>> col_sum(200001);

// 입력값이 100만 -> nlogn 으로 끝내야 한다.
int main() {
	int n;
	scanf("%d", &n);

	LL a, b;
	queue<pii> q;
	
	for (int i = 0; i < n; i++) {
		scanf("%lld %lld", &a, &b);
		v[a].push_back(b);
		arr[b] += 1;
		q.push({ a,b });
	}
	
	// 전체 합 구하기
	for (LL i = 1; i <= 2000; i++) 
		all_sum[i] = i * arr[i] + all_sum[i - 1];

	// color 별 합 메모
	for (int i = 1; i <= n; i++) {
		if (v[i].empty()) continue;
		sort(v[i].begin(), v[i].end());
		for (int j = 0; j < v[i].size(); j++) {
			if (j == 0) {
				col_sum[i].push_back(v[i][j]);
				continue;
			}
			col_sum[i].push_back(col_sum[i].back() + v[i][j]);
		}
	}
	

	pii cur;
	while (!q.empty()) {
		cur = q.front();
		q.pop();
		LL sum = 0;
		int idx = lower_bound(v[cur.first].begin(), v[cur.first].end(), cur.second) - v[cur.first].begin();
		if (idx == 0) 
			sum = 0;
		else 
			sum = col_sum[cur.first][idx - 1];
		LL ans = all_sum[cur.second - 1] - sum;
		printf("%lld\n", (ans < 0) ? 0 : ans);
	}
	
	return 0;
}
#define _CRT_SECURE_NO_WARNINGS

#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <string.h>
#include <math.h>

using namespace std;
typedef long long LL;
typedef pair<int, int> pii;

LL input;
LL col_sum[200001];
LL size_sum[2001];

struct Ball {
	int idx;
	LL col, val;
	LL ret;
};

bool cmp(Ball &a, Ball &b) {
	if (a.val == b.val) {
		return a.col < b.col;
	}
	return a.val < b.val;
}
bool cmp1(Ball& a, Ball& b) {
	return a.idx < b.idx;
}
// 입력값이 100만 -> nlogn 으로 끝내야 한다.
int main() {
	int n, a, b;
	scanf("%d", &n);
	vector<Ball> all_arr(n);

	for (int i = 0; i < n; i++) {
		scanf("%lld %lld", &all_arr[i].col, &all_arr[i].val);
		all_arr[i].idx = i;
	}
	
	sort(all_arr.begin(), all_arr.end(), cmp);

	LL sum = 0;
	for (int i = 0; i < n; i++) {
		LL col = all_arr[i].col;
		LL val = all_arr[i].val;

		// 해당 색의 현재 누적합
		col_sum[col] += val;
		
		// 같은 크기의 누적합
		size_sum[val] += val;

		// 전체의 현재 누적합
		sum += val;

		all_arr[i].ret = sum - col_sum[col] - size_sum[val] + val;
		if (i != 0 && col == all_arr[i - 1].col && val == all_arr[i - 1].val) {
			all_arr[i].ret = all_arr[i - 1].ret;
		}
	}
	sort(all_arr.begin(), all_arr.end(), cmp1);

	for (int i = 0; i < n; i++) {
		printf("%lld\n", all_arr[i].ret);
	}

	return 0;
}
 

10800번: 컬러볼

첫 줄에는 공의 개수를 나타내는 자연수 N이 주어진다(1 ≤ N ≤ 200,000). 다음 N개의 줄 중 i번째 줄에는 i번째 공의 색을 나타내는 자연수 Ci와 그 크기를 나타내는 자연수 Si가 주어진다(1 ≤ Ci ≤ N

www.acmicpc.net

 

'책장 > 알고리즘' 카테고리의 다른 글

[백준-14391] 종이조각  (0) 2021.10.01
[백준-19951] 태상이의훈련소생활  (0) 2021.09.30
[백준-10986] 나머지 합  (0) 2021.09.29
[백준-11659]구간합구하기4  (0) 2021.09.29

누적합과 조합 계산식이 필요한 문제다.

일단 입력값을 보면 100만임을 봐서 최소 O(NlogN) 의 복잡도 내로 끝내야 함을 알 수 있다. 허나 이 문제의 경우 각 누적합을 통해 O(N) 복잡도로 끝낼 수 있다. 로직은 다음과 같다.

  • 입력되는 배열을 순서대로 sum 배열에 넣되 m으로 나눈 나머지 값을 쭉 넣어준다.
  • sum 배열을 순회하면서 원소를 pai 배열에 체킹해준다.
  • pai 배열에 체킹된 순서로 순회하면서 조합식을 더하면 답이 된다.

이렇게 pai 배열을 둔 이유는 sum[i] - sum[j] = 0 이 되는 경우의 수를 찾아야 하는데 결국 sum[i] == sum[j] 인 경우를 찾는 것과 다름이 없다. 따라서 같은 값을 가지는 sum 배열의 원소들을 쭉 체킹해준 다음 nC2의 조합식에 따라 단순 계산해주게 되면 답이 나오게 된다.

#define _CRT_SECURE_NO_WARNINGS

#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <string.h>
#include <math.h>
using namespace std;
typedef long long LL;

LL input;
LL sum[1000001];
LL pai[1001];
// 입력값이 100만 -> nlogn 으로 끝내야 한다.
int main() {
	int n;
	LL m;
	scanf("%d %lld", &n, &m);
	for (int i = 1; i <= n; i++) {
		scanf("%lld", &input);
		sum[i] = sum[i - 1] + (input % m);
		sum[i] %= m;
	}
	
	for (int i = 1; i <= n; i++) 
		pai[sum[i]] += 1;
	
	LL res = 0;
	for (LL i = 0; i < m; i++) {
		if (!pai[i]) continue;
		if (i == 0) {
			res += (pai[i] * (pai[i] - 1)) / 2;
			res += pai[i];
		}
		else {
			res += (pai[i] * (pai[i] - 1)) / 2;
		}
	}
	printf("%lld", res);
	return 0;
}
 

10986번: 나머지 합

수 N개 A1, A2, ..., AN이 주어진다. 이때, 연속된 부분 구간의 합이 M으로 나누어 떨어지는 구간의 개수를 구하는 프로그램을 작성하시오. 즉, Ai + ... + Aj (i ≤ j) 의 합이 M으로 나누어 떨어지는 (i, j)

www.acmicpc.net

 

'책장 > 알고리즘' 카테고리의 다른 글

[백준-19951] 태상이의훈련소생활  (0) 2021.09.30
[백준-10800] 컬러볼  (0) 2021.09.30
[백준-11659]구간합구하기4  (0) 2021.09.29
[백준-15724] 주지수  (0) 2021.09.28