AOJ - OCR

이 문제는 꽤 난이도가 있다.

$dp[i][k]$ 를 $i$ 번째에 $k$ 번 째 단어를 뒀을 때, 끝까지 갈 때 가장 원문이 될 확률이 높은 값

이라고 하자.

사실 점화식 자체의 유도가 어렵진 않다 값이 복잡해서 그렇지

놀랐던건 종만북의 설명이 너무나 복잡하단 점이다.

void solve() {  
   int n, q;  
   cin >> n >> q;  
  
   vector<string> s(n);  
   fv(s);  
   map<string, int> idx;  
   for (int i = 0; i < n; i++) idx[s[i]] = i;  
  
   vector<double> start(n);  
   fv(start);  
  
   vector<vector<double>> nxt(n, vector<double>(n)), classify(n, vector<double>(n));  
   fv2(nxt);  
   fv2(classify);  
   while (q--) {  
      int m;  
      cin >> m;  
      vs t(m);  
      fv(t);  
  
      vector<vector<double>> dp(m, vector<double>(n, -1));  
      function<double(int, int)> fn = [&](int i, int k) -> double {  
         double &ret = dp[i][k];  
         if (ret > -0.5) return ret;  
         ret = 0;  
         if (i == m - 1) return ret = 1;  
         for (int j = 0; j < n; j++) {  
            ret = max(ret, nxt[k][j] * fn(i + 1, j) * classify[j][idx[t[i + 1]]]);  
         }  
         return ret;  
      };  
      vector<double> fi;  
      for (int i = 0; i < n; i++) {  
         fi.pb(fn(0, i) * start[i] * classify[i][idx[t[0]]]);  
      }  
      vector<string> ans;  
      function<void(int, int)> trace = [&](int i, int k) -> void {  
         ans.pb(s[k]);  
         if (i == m - 1)return;  
         for (int j = 0; j < n; j++) {  
            double tmp1 = fn(i, k);  
            double tmp = nxt[k][j] * fn(i + 1, j) * classify[j][idx[t[i + 1]]];  
            if (tmp1 == tmp) {  
               trace(i + 1, j);  
               break;  
            }  
         }  
      };  
  
      int initial = maxi(fi);  
      trace(0, initial);  
      for (string k: ans) cout << k << ' ';  
      cout << endl;  
   }  
}

Comments