Hello Ocean! 🌼

[μ•Œκ³ λ¦¬μ¦˜ μŠ€ν„°λ””] λ°±μ€€ #2531 νšŒμ „μ΄ˆλ°₯ λ³Έλ¬Έ

Algorithm

[μ•Œκ³ λ¦¬μ¦˜ μŠ€ν„°λ””] λ°±μ€€ #2531 νšŒμ „μ΄ˆλ°₯

bba_dda 2020. 4. 4. 00:16
λ°˜μ‘ν˜•

[문제]

νšŒμ „ν•˜λŠ” 벨트 μœ„μ— μœ„μ™€ 같이 초λ°₯듀이 μžˆλ‹€. 벨트 μœ„μ—λŠ” 같은 μ’…λ₯˜μ˜ 초λ°₯이 μ—¬λŸ¬κ°œ μžˆμ„ 수 μžˆλ‹€.

μ†λ‹˜μ€ 초λ°₯을 κ³¨λΌμ„œ 먹을 것이닀. 

1. μ—°μ†μœΌλ‘œ kμ ‘μ‹œλ₯Ό 먹을 경우, ν• μΈλœ 가격을 μ§€λΆˆν•œλ‹€.

2. 각 κ³ κ°μ—κ²Œ 초λ°₯ μ’…λ₯˜ 쀑 ν•˜λ‚˜κ°€ 쓰여진 쿠폰을 λ°œν–‰ν•˜κ³ , μ†λ‹˜μ΄ 1번 행사에 μ°Έκ°€ν•  경우 ν•΄λ‹Ή 초λ°₯ 1μ ‘μ‹œλ₯Ό 무료둜 μ œκ³΅ν•œλ‹€. 벨트 μœ„μ— ν•΄λ‹Ή 초λ°₯이 없을 경우 μƒˆλ‘œ λ§Œλ“€μ–΄ μ œκ³΅ν•œλ‹€.

μ†λ‹˜μ€ μœ„μ˜ 행사에 μ°Έμ—¬ν•˜μ—¬ μ΅œλŒ€ν•œ λ‹€μ–‘ν•œ μ’…λ₯˜μ˜ 초λ°₯을 먹으렀고 ν•œλ‹€. 

 

[input]

λ²¨νŠΈμ— 놓인 μ ‘μ‹œμ˜ 수 N ( 2 ≤ N ≤ 30000 )

초λ°₯의 κ°€μ§“μˆ˜ d ( 2 ≤ d ≤ 3000 )

μ—°μ†ν•΄μ„œ λ¨ΉλŠ” μ ‘μ‹œμ˜ 수 k ( 2 ≤ k ≤ 3000 (k ≤ N) )

쿠폰번호 c ( 1 ≤ c ≤ d )

 

N d k c

초λ°₯ μ’…λ₯˜ (ν•œμ€„μ”©)

 

[output]

주어진 νšŒμ „ 초λ°₯ λ²¨νŠΈμ—μ„œ 먹을 수 μžˆλŠ” 초λ°₯ κ°€μ§“μˆ˜μ˜ μ΅œλŒ“κ°’

 

[풀이]

첫 번째.

count 와 kind배열을 λ§Œλ“€μ–΄μ„œ μ΄μš©ν•˜μž.

count  = [start~cκ°€ λ‚˜μ˜¬ λ•Œ κΉŒμ§€ μ ‘μ‹œ 개수, ... , c~c μ ‘μ‹œ 개수, ... , c~end μ ‘μ‹œ 개수]

kind = [start~cκ°€ λ‚˜μ˜¬ λ•Œ κΉŒμ§€ 초λ°₯ μ’…λ₯˜, ... , c~c 초λ°₯ μ’…λ₯˜, ... , c~end 초λ°₯ μ’…λ₯˜]

c=30

 

μ΄λ ‡κ²Œ ν•˜λ©΄ μ–΄λ–€ κ²½μš°μ—μ„œλŠ” λΉ λ₯΄κ²Œ output을 ꡬ할 수 μžˆμ§€λ§Œ, μ—¬μ „νžˆ 완전탐색을 ν•΄μ•Όν•˜λŠ” κ²½μš°κ°€ μ‘΄μž¬ν•˜μ˜€λ‹€. 

μ™„μ „νƒμƒ‰μ˜ 경우 μ΅œμ•…μ˜ λ³΅μž‘λ„κ°€ O(N*k) = 3000000 * 3000 = 90μ–΅ μ΄λ―€λ‘œ μ‹œκ°„μ΄ˆκ³Όκ°€ λ°œμƒν•œλ‹€.

 

두 번째.(μ΅œμ’…)

이 λ¬Έμ œμ— κ΄€ν•΄ μ‘°μ‚¬ν•˜λ˜ 쀑 'μŠ¬λΌμ΄λ”© μœˆλ„μš°' κΈ°λ²•μœΌλ‘œ ν’€μ–΄μ•Ό ν•œλ‹€λŠ” 것을 μ•Œκ²Œλ˜μ—ˆλ‹€. 

μ§€λ‚œλ²ˆ μŠ€ν„°λ””μ—μ„œ λ‚˜μ™”λ˜ 기법인데, μ™„μ „νƒμƒ‰κ³Όμ˜ λ‹€λ₯Έ 점을 μ΄ν•΄ν•˜μ§€ λͺ»ν•΄ λ‚˜μ€‘μ— 곡뢀할 κ²ƒμœΌλ‘œ λ―Έλ€„λ‘μ—ˆλ˜ μ•Œκ³ λ¦¬μ¦˜μ΄λ‹€. 

μŠ¬λΌμ΄λ”© μœˆλ„μš°λŠ” μœˆλ„μš°κ°€ λ―Έλ„λŸ¬μ§€λ“―μ΄ λ°°μ—΄μ˜ 첫 λΆ€λΆ„ λΆ€ν„° 끝 λΆ€λΆ„κΉŒμ§€ νƒμƒ‰ν•˜λŠ” μ•Œκ³ λ¦¬μ¦˜μ΄λ‹€.

μœ„μ˜ μž…λ ₯을 μ˜ˆλ‘œλ“€λ©΄ μ΄λŸ°μ‹μœΌλ‘œ νƒμƒ‰ν•˜κ²Œ λœλ‹€. 

 

μ—¬κΈ°κΉŒμ§€λ§Œ 보면 완전탐색과 무엇이 λ‹€λ₯Έμ§€ 의문이 λ“€κΈ° μ‹œμž‘ν•œλ‹€.

μŠ¬λΌμ΄λ”© μœˆλ„μš°λŠ” O(n)의 λ³΅μž‘λ„λ₯Ό κ°€μ§€λŠ”λ°, 맀번 k개의 μ ‘μ‹œλ₯Ό λͺ¨λ‘ κ²€μ‚¬ν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ΄λ‹€. 

- 방금 λΊ€ μŠ€μ‹œμ˜ μ’…λ₯˜κ°€ 더 이상 μœˆλ„μš°μ— μ—†μœΌλ©΄ count-=1

- 방금 μƒˆλ‘œ λ“€μ–΄μ˜¨ μŠ€μ‹œμ˜ μ’…λ₯˜κ°€ μ›λž˜ μœˆλ„μš°μ— μ—†λ˜ 것이면 count+=1

- ν˜„μž¬μ˜ μœˆλ„μš° μ•ˆμ— c번(쿠폰)μŠ€μ‹œκ°€ 없을 경우 count+=1

ν•΄μ„œ 이전 μœˆλ„μš°μ˜ countκ°’κ³Ό λΉ„κ΅ν•˜μ—¬ 더 ν°κ°’μœΌλ‘œ μœ μ§€μ‹œμΌœμ„œ λκΉŒμ§€ λ°˜λ³΅ν•˜λ©΄ λœλ‹€.

ν•œ μœˆλ„μš° λ‚΄μ˜ 연산이 μƒμˆ˜λ²ˆμœΌλ‘œ λλ‚˜κΈ° λ•Œλ¬Έμ— O(n)의 λ³΅μž‘λ„λ₯Ό κ°€μ§€λŠ” 것이닀. 

 

μœˆλ„μš°λŠ” 계속 맨 μ•žμ— μ›μ†Œλ₯Ό μ œκ±°ν•˜κ³ , 맨 뒀에 λ‹€λ₯Έ μ›μ†Œλ₯Ό μΆ”κ°€ν•˜λŠ” λ°©μ‹μœΌλ‘œ μ—°μ‚°λ˜κΈ° λ•Œλ¬Έμ— C++ STL queue 자료ꡬ쑰λ₯Ό μ‚¬μš©ν•˜μ˜€λ‹€. 

 

[μ΅œμ’… μ½”λ“œ]

#include <stdio.h>
#include <algorithm> //max()λ₯Ό μœ„ν•œ ν—€λ”νŒŒμΌ 
#include <queue>
#include <memory.h> //memset을 λ°±μ€€μ—μ„œ μ‚¬μš©ν•˜κΈ° μœ„ν•œ ν—€λ”νŒŒμΌ
using namespace std;

int n, d, k, c;
int belt[3000000]; 
int kind[3000]; 
int i, j;
queue<int> window;

int slidingWindow() {
	int maxcount;
	int count = 0;
	int temp;
	for (int i = 0;i < k;i++) {
		temp = belt[i];
		window.push(temp);
		if (kind[temp - 1] == 0)
			count++;
		kind[temp - 1]++;
	}
	if (kind[c - 1] == 0)
		maxcount = count + 1;
	else
		maxcount = count;
	for (int i = k;i < n+k;i++) {
		int tempcount = count;
		//맨 μ•žμ— 있던 μ ‘μ‹œ 확인 ν›„ 제거
		int front = window.front();
		kind[front - 1]--;
		if (kind[front-1]==0)
			tempcount--;
		window.pop();

		//μƒˆλ‘œμš΄ μ ‘μ‹œ μΆ”κ°€ 
		temp = belt[i%n];
		window.push(temp);
		if (kind[temp - 1] == 0)
			tempcount++;
		kind[temp - 1]++;
		//쿠폰 초λ°₯을 아직 먹지 μ•Šμ•˜μ„ λ•Œ 
		if (kind[c - 1] == 0)
			maxcount=max(maxcount,tempcount+1);
		else
			maxcount = max(maxcount, tempcount);
	
		count = tempcount;
	}
	return maxcount;
}
int main() {
	memset(belt, 0, sizeof(belt));
	scanf_s("%d", &n);
	scanf_s("%d", &d);
	scanf_s("%d", &k);
	scanf_s("%d", &c);
	for (int i = 0;i < n;i++) {
		scanf_s("%d", &belt[i]);
	}
	printf("%d", slidingWindow());
}

[κ³ λ €ν•  점]

1. slidingWindow()μ—μ„œ for문을 돌릴 λ•Œ, k~n-1κΉŒμ§€κ°€ μ•„λ‹ˆλΌ, n~n+k-1(n번)λŒλ €μ•Ό ν•˜λŠ” 점이 μ€‘μš”

2. μš°λ¦¬κ°€ μ‚¬μš©ν•˜λŠ” 배열은 처음과 끝이 μžˆλŠ” λͺ¨μ–‘μ΄μ§€λ§Œ, μ‹€μ œλ‘œ 벨트 ν˜•νƒœλ‘œ κ΅¬μ„±λ˜μ–΄ 있기 λ•Œλ¬Έμ— belt[i%n]둜 μ ‘κ·Όν•˜λŠ” 것이 μ€‘μš”

3. 쿠폰 초λ°₯을 μƒˆλ‘œ λ§Œλ“€μ–΄λ¨Ήμ–΄μ•Ό ν•˜λŠ”μ§€ μ•„λ‹Œμ§€λŠ” 맀 windowλ§ˆλ‹€ λ‹€λ₯΄κΈ° λ•Œλ¬Έμ—, tempcount에 λ”ν•΄λ²„λ €μ„œ λ„˜κΈ°κ²Œ 되면 λ‹€μŒ windowκ°€ 영ν–₯을 λ°›λŠ”λ‹€. λ”°λΌμ„œ λ³€μˆ˜μ— λ”ν•˜μ§€ 말고 if문을 μ΄μš©ν•΄ μ•„λž˜μ™€ 같이 μž‘μ„±ν•΄μ•Όν•¨

if (kind[c - 1] == 0)
    maxcount=max(maxcount,tempcount+1);
else
    maxcount = max(maxcount, tempcount);
count = tempcount;

μŠ¬λΌμ΄λ”© μœˆλ„μš°λ‘œ ν’€ 수 μžˆλ‹€λŠ” 것을 λͺ°λžμœΌλ©΄, 이틀밀을 μƒˆλ„ 풀지 λͺ»ν–ˆμ„ 것 같은 λ¬Έμ œμ˜€λ‹€. 

λ°˜μ‘ν˜•