CodeForce - Hard problem(706C)

문제(링크)
문제 설명:
N개의 문자열이 주어지고, 각 문자열마다 문자열을 반전시키는 비용도 주어집니다.

문자열을 반전시키거나 반전시키지 않고, 문자열을 사전식으로 정렬해야 할 때, 반전 비용의 최소값을 구하는 문제입니다.
중간에 prefix 관련 설명은
aa
aab
위 순서대로 정렬해야 한다는 뜻입니다. 만약
z
aa
이라면 -1을 출력해야 합니다. --> compare 함수에서 자동으로 판단해 줍니다.
풀이:
원본 문자열과 반전 문자열 두 개를 준비합니다.(문자열 길이의 총 합이 100000이하이므로 가능합니다.)

dp[x][0 or 1] = x번째 문자열에서 이전 문자열을 0 = 반전x , 1 = 반전o

이전 문자열과, 현재 문자열을 반전시키거나 그대로 두면서 재귀 호출합니다.
반전시킬 경우에만 energy값을 더해줍니다.



#include<iostream>
#include<algorithm>
#include<math.h>
#include<string.h>
#include<string>
#include<vector>
#include<queue>
using namespace std;
#define FIO ios_base::sync_with_stdio(false); cin.tie(NULL)
#define ll long long
#define pii pair<int, int>
#define MAX 1000000000000000000LL

int N;
ll energy[100001];
string str[100001][2];
ll dp[100002][2];

ll recul(int now,int order) {

 if (now == N + 1) {
  return 0;
 }

 ll& ret = dp[now][order];
 //dp 메모이제이션
 if (ret != -1) return ret;
 ret = 0;
 ll o = MAX;
 ll r = MAX;
 
 if (str[now][0].compare(str[now - 1][order]) >= 0) {
  //원본 문자열과 비교
  o = recul(now + 1, 0);
 }
   
 if (str[now][1].compare(str[now - 1][order]) >= 0) {
  //반전해서 비교 - energy값이 필요
  r = recul(now + 1, 1) + energy[now];
 }

 return ret = min(o, r);
 //둘 중 작은 값을 return
}

int main(void) {
 FIO;

 cin >> N;

 for (int i = 1; i <= N; i++)
 {
  cin >> energy[i];
 }
 for (int i = 1; i <= N; i++)
 {
  cin >> str[i][0];
  str[i][1] = str[i][0];
  reverse(str[i][1].begin(), str[i][1].end());
 }
 memset(dp, -1, sizeof(dp));

 ll ans = recul(1, 0);
 
 if (ans == MAX)
  cout << "-1";
 else
  cout << ans;
}

댓글

이 블로그의 인기 게시물

HTML - input file 버튼 꾸미기

HTML - 이미지 미리보기(jQuery 없이)

BOJ - DNA 유사도(2612)