Codeforces 92C (123C) Brackets
問題
各成分が'('または')'であるnxmの行列が、monotonusであるとは、
(1, 1)から右または下に動いて(n, m)へ辿り着いたときにできる括弧文字列が、
どのような動き方をしたとしても対応していることを言う。
monotonusであるような行列を、c[i][j]にしたがって順序をつける。
行列a, bについて、a[i][j] != b[i][j]なる(i, j)のうち、c[i][j]が最小である(i, j)について、
a[i][j] < b[i][j]ならa < bとする。
このような順序をつけて、可能なmonotonusな行列をすべて並べたとき、
k番目に来るものを求めよ。
制約条件
n, m≦100
k≦10^8
1≦p[i][j]≦nmかつすべてのp[i][j]は異なる整数
方針
(i, j)には、(i - 1, j)と(j, i - 1)のどちらからも来られるため、
全てのi, jについて、a[i - 1][j]とa[i][j - 1]が等しい。
したがって、/の向きの斜めの線上に並ぶ要素は全部等しい。
逆にこの条件を見たすなら、どのようにたどっても順路の文字列は同じなので、
ひとつの経路を確かめて、括弧の対応が取れていればmonotonus.
なので、長さn + m - 1の文字列で、順序がk番目のものをもとめればよい。
これは1文字ずつ決めうちして、DPしてく典型的な方法が使える。
文字列のうち、i番目に優先度が高い添え字をo[i]とする。
o[i]を'('に固定して、文字列がk通り作れないなら、o[i]は')'
(残りの文字は未確定にしておいて、何通りあるかはDPで簡単に求まる)
ソースコード
int n, m, p[200][200]; ll k; ll dp[201][201]; ll calc(const string &s){ int n = s.size(); memset(dp, 0, sizeof(dp)); dp[0][0] = 1; rep(i, n) rep(j, i + 1) if(dp[i][j]){ rep(k, 2){ if(s[i] == '(' && k == 0 || s[i] == ')' && k == 1) continue; int nj = j + (k ? 1 : -1); if(nj < 0) continue; dp[i + 1][nj] = min(dp[i + 1][nj] + dp[i][j], inf); } } return dp[n][0]; } int main(){ cin >> n >> m >> k; rep(i, n) rep(j, m){ cin >> p[i][j]; int k = min(i, m - j - 1); p[i - k][j + k] = min(p[i - k][j + k], p[i][j]); } vi o; vector<pi> v; rep(i, m - 1) v.pb(mp(p[0][i], v.size())); rep(i, n) v.pb(mp(p[i][m - 1], v.size())); sort(all(v)); int l = v.size(); rep(i, l) o.pb(v[i].second); string s(l, '?'); rep(i, l){ s[o[i]] = '('; ll w = calc(s); if(w < k) s[o[i]] = ')', k -= w; } rep(i, n) rep(j, m) cout << s[i + j] << (j==m-1?"\n":""); return 0; }