题目描述
最近美国人致力于掀翻华尔街的资本家们,因为他们的生活并不太好,可是那些资本家却依然过着奢华的享乐生活。一些人在游行,而另一些人则试图揭开华尔街的金融家们获取财富的秘密,终于,白宫发现了这个秘密,那就是——一个括号矩阵!!!
所谓括号矩阵,就是一个
n
×
m
n \times m
n×m 的矩阵,其中的每一个元素要么是 (
,要么是 )
。矩阵中有公共边的格子是相邻的。从矩阵的左上角
(
1
,
1
)
(1, 1)
(1,1) 到右下角
(
n
,
m
)
(n, m)
(n,m) 的一条路径,如果满足下一步要么走到右边相邻的格子,要么走到下边相邻的格子,它就是一条最短路径。一条路径是合法的,当且仅当它形成的括号序列是可以匹配的,例如 (())()
、()
、(()(()))
等等都是可匹配的,而 )(
、(()
、(()))(
等等是不可匹配的。一个括号矩阵合法,当且仅当其所有的最短路径合法。
现在,我们定义两个大小相等的合法括号矩阵 a a a 和 b b b 的比较。 c c c 数组是和括号矩阵大小相等的矩阵,规模也是 n × m n \times m n×m,其中的元素是 1 ∼ n × m 1 \sim n \times m 1∼n×m 间整数,且互不相同,即 n × m n \times m n×m 个整数出现且仅出现了一次。找到满足如下条件的 i , j i, j i,j, a i , j ≠ b i , j a_{i, j} \neq b_{i, j} ai,j=bi,j,且 c i , j c_{i, j} ci,j 最小。若 a i , j = ′ ( ′ a_{i, j} = '(' ai,j=′(′, 则 a < b a < b a<b,否则 a > b a > b a>b。
现在奥巴马已经得知某个括号矩阵里面藏着金融家们的致富密码,他会告诉你三个整数 n , m , k n, m, k n,m,k,你需要找出第 k k k 小的 n × m n \times m n×m 的矩阵,这就是那个秘密矩阵。
输入格式
输入第一行有三个整数 n , m , k n,m,k n,m,k。
接下来有 n n n 行,每行 m m m 个数,第 i i i 行第 j j j 个数表示 c i , j c_{i, j} ci,j。
输出格式
输出一个 n × m n \times m n×m 的矩阵,由 ( ( ( 和 ) ) )组成。
样例
样例输入1:
1 2 1
1 2
样例输出 1:
()
数据范围
n , m ≤ 1000 , k ≤ 1 0 18 n, m \le 1000, k \le 10^{18} n,m≤1000,k≤1018
1 ≤ c i , j ≤ n × m 1 \le c_{i, j} \le n \times m 1≤ci,j≤n×m, c c c 中所有元素保证不同。
保证存在答案矩阵。
题解
题目要求每一个最短路径都是合法的,因此,每个左下到右上的对角线是相同的(因为从某个位置向下向右走到相同的格子,对角线相等)。这样把一个矩阵映射成一个一维序列。
找第 k k k 小的序列, k k k 很大,考虑计数dp。设 f i , j f_{i, j} fi,j 表示到第 i i i 个位置 j j j 个左括号未匹配。 f i , j = f i − 1 , j − 1 + f i − 1 , j + 1 f_{i, j} = f_{i - 1, j - 1} + f_{i - 1, j + 1} fi,j=fi−1,j−1+fi−1,j+1。
按照
c
c
c 的大小依次确定每一位是 (
还是 )
,具体做法就是把这个位置设为 (
,看方案数是否超过
k
k
k,没有超过就改为 )
。
#include<bits/stdc++.h>
using namespace std;
long long n, m, K;
struct node{
long long x, y;
}a[210];
bool cmp(node p, node q){
return p.x < q.x;
}
long long f[210][210], fl[210];
int main(){
scanf("%lld %lld %lld", &n, &m, &K);
for(int i = 1; i <= 200; ++ i){
a[i].x = 1e16;
}
for(long long i = 1; i <= n; ++ i){
for(long long j = 1; j <= m; ++ j){
long long x;
scanf("%lld", &x);
a[i + j - 1].x = min(a[i + j - 1].x, x);//映射
}
}
n = n + m - 1;
for(long long i = 1; i <= n; ++ i){
a[i].y = i;
}
sort(a + 1, a + n + 1, cmp);//按c排序
for(long long i = 1; i <= n; ++ i){
//dp
f[0][0] = 1;
fl[a[i].y] = 1;
for(long long j = 1; j <= n; ++ j){
for(long long k = 0; k <= j; ++ k){
if(fl[j] == 1){//已经确定
f[j][k] = f[j - 1][k - 1];
}
else if(fl[j] == 2){//已经确定
f[j][k] = f[j - 1][k + 1];
}
else{
f[j][k] = f[j - 1][k - 1] + f[j - 1][k + 1];
}
f[j][k] = min(f[j][k], K);
}
}
if(f[n][0] >= K){
fl[a[i].y] = 1;
}
else{
fl[a[i].y] = 2;
K -= f[n][0];
}
}
n = n - m + 1;
for(long long i = 1; i <= n; ++ i){
for(long long j = 1; j <= m; ++ j){
if(fl[i + j - 1] == 1){
putchar('(');
}
else{
putchar(')');
}
}
putchar('\n');
}
return 0;
}