思路

我们注意到答案串一定是若干个可以变成一个可以做出 $k$ 个合法的括号序列的长度 $\le n$ 的序列再补上若干个 )

显然,设答案串 $s$ 有 $k$ 对括号在最外层,那么合法子串个数为 $\frac{k(k+1)}{2}$。我们就可以构造了!

这样就可以在不浪费括号的情况下将答案串分成多个括号串。

设 $dp_i$ 为构造出 $i$ 个合法子串(即 $k$)所需的最小括号对数。

状态转移就是:$dp_i=dp_{i-\frac{j(j+1)}{2}}+j$。

我们先把这部分预处理出来。

如果 $2dp_k>n$ 则说明无解,否则在 dp 数组上递归构造(如果$dp_i=dp_{i-\frac{j(j+1)}{2}}+j$,那么就转移)。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include<bits/stdc++.h>
#define int long long
using namespace std;
int T,n,k,dp[100005];
void print(int x){
if(!x) return;
for(int i=1;i*(i+1)/2<=x;i++)if(dp[x-i*(i+1)/2]+i==dp[x])
{for(int j=1;j<i;j++) cout<<"()";cout<<"(",print(x-i*(i+1)/2),cout<<")";return;}
}signed main(){
cin>>T,memset(dp,0x3f,sizeof dp),dp[0]=0;
for(int i=1;i<=100000;i++)
for(int j=1;j*(j+1)/2<=i;j++) dp[i]=min(dp[i],dp[i-j*(j+1)/2]+j);
while(T--){
cin>>n>>k;if(dp[k]*2>n){cout<<"-1\n"; continue;}
print(k);for(int i=dp[k]*2+1;i<=n;i++)cout<<")";cout<<'\n';
}
}