카테고리 없음

BOJ 1256: 사전

wifilion 2024. 10. 9. 16:27

요즘 DP로 기초를 탄탄히 하는 중이다. 사실 DP만 잘하면 다 잘한다고 할 수 있을 것 같다. DP는 어디에도 없고 어디에도 있다.

본론으로 돌아와, 사전은 조합론 DP 문제이다. 조합론 DP는 대부분 파스칼의 삼각형을 DP로 점화식 세워 푸는 문제들이다.

이 문제도 마찬가지다. 언뜻 보면 오버플로 때문에 "어떤 병신이 그걸 파스칼로함? ㅋㅋ"이라 생각할 수 있지만, 상한이 있기 때문에 그냥 상한 조건을 전파하고 적절한 처리를 해주면 그만이다.

즉, big 태그에 대해, 얘가 붙으면 어짜피 뭘 해도 현재 K보다 크므로 a붙이고... 이런 식이다. 

코드를 보자. 코드가 직관적이라 이해하긴 쉬울 듯하다.

#include<bits/stdc++.h>
#define INF 1000000000
using namespace std;
typedef long long int ll;
ll N, M, K;
ll C[201][201];
bool big[201][201];
string s;
int main(){
	for(int i=0;i<201;i++) memset(big[i], false, sizeof(big[i]));
	cin >> N >> M >> K;
	for(int i=0;i<201;i++){
		C[i][0]=1; 
		C[i][i]=1;
	}
	for(int i=2;i<=200;i++){
		for(int j=1;j<=i/2;j++){
			C[i][j]=C[i-1][j-1]+C[i-1][j];
			if(big[i-1][j-1] or big[i-1][j]){
				big[i][j]=true;
			}
			else if(C[i][j]>INF){
				big[i][j]=true;
			}
			C[i][i-j]=C[i][j];
			big[i][i-j]=big[i][j];
		}
	} // Overflow;; 자명히
	int A=N, Z=M; // A, D의 개수
	if(!big[A+Z][Z] and K>C[A+Z][Z]){
		cout << "-1";
		return 0;
	} // 미리 처리: big면 무조건 포함
	K--;
	for(int i=0;i<N+M;i++){
		if(A==0){
			s+="z";
			Z--;
			continue;
		}
		else if(Z==0){
			s+="a";
			A--;
			continue;
		}
		if(big[A+Z-1][Z]){
			s+="a";
			A--;
		}
		else if(K>=C[A+Z-1][Z]){
			s+="z";
			K-=C[A+Z-1][Z];
			Z--;
		}
		else if(K<C[A+Z-1][Z]){
			s+="a";
			A--;
		}
	}
	cout << s;
}

 

확률과 통계를 배우지 않은 PS인은 없으리라 믿는다.

사실 나도 확통을 못해서 색상환을 틀려먹은거긴 한데, 무튼.

행복한 한글날? 되세요 / ^ o ^ /