题意
牛客网
构造一个非空括号字符串,要求正好包含k个合法括号对
且字符串长度不能超过十万
* 0 ≤ k ≤ 1 0 9 0\leq k \leq 10^9 0≤k≤109
思路
看到这个k的数据范围和字符串长度要求,我们知道不能一个劲怼括号,否则会超出长度限制
那么我们先来思考一个问题:
一个长度为n的字符串,如何出现最多的括号对?(为了方便描述,我假定n为偶数)
答案是把字符串一分为二,左边全是左括号,右边全是右括号,这样我们就得到了 ( n 2 ) 2 (\frac{n}{2})^2 (2n)2个括号对。
把上面这个过程反过来,我们需要正好
k
k
k个合法括号对,那么我们先令
t
=
k
(
向
下
取
整
)
t=\sqrt{k} (向下取整)
t=k(向下取整),字符串左边放入
t
t
t个左括号,右边放入
t
t
t个右括号,那么我们就得到了
t
2
t^2
t2个括号对。
因为
t
t
t是向下取整的,所以我们可能会漏掉一些括号对,这时候需要把漏掉的括号对补上。
我们需要补上
d
e
l
t
a
=
k
−
t
2
delta = k-t^2
delta=k−t2个括号对,因为字符串右边有
t
t
t个右括号,所以我们每在字符串左边加一个左括号就会增加
t
t
t个括号对。
在字符串左边加上
d
e
l
t
a
/
t
(
向
下
取
整
)
delta / t(向下取整)
delta/t(向下取整)个括号对以后,我们还需要补上
d
e
l
t
a
%
t
delta \% t
delta%t个括号对。这时候不能再去字符串左边加左括号,因为这么做得到的括号对会大于
k
k
k。这样,我们就要从字符串的右边入手。
字符串右边现在是 t t t右括号,我们需要补上的括号对又小于 t t t,所以我们可以从右往左数 d e l t a % t delta \% t delta%t个位置,从那里插入一个左括号,这样整个字符串就增加了 d e l t a % t delta \% t delta%t个右括号,得到了刚好 k k k个合法括号对。
例子:
k
=
7
k=7
k=7,先生成字符串 (()),再从字符串左边补上
d
e
l
t
a
/
t
=
2
delta / t=2
delta/t=2个括号对,变成((()),还差一个括号对,从字符串从右往左数第
d
e
l
t
a
%
t
delta \% t
delta%t个位置插入左括号,得到((()(),正好7个合法括号对
代码
#include <iostream>
#include <cmath>
using namespace std;
int main() {
int k;
cin >> k;
//如果k=0则输出包含0个合法括号对的非空括号字符串
if (k == 0) {
cout << ")";
return 0;
}
//k开根号先生成一些括号对
int t = (int) sqrt(k);
//实际需要的括号对和当前括号对数量的差值
int delta = k - t * t;
//在最左边每添加一个"("就会多出t对合法括号对
for (int i = 0; i < delta / t; ++i) {
cout << "(";
}
//原有的t个"("
for (int i = 0; i < t; ++i) {
cout << "(";
}
//加了整数倍t个括号对以后还差delta个括号对
delta = delta % t;
//先输出原有的t个")"
//从右往左数,差几个括号对就从第几个位置插入一个"("
//如果不差括号对就不再插入(这里放在了最后一个)
for (int i = 0; i < t + 1; ++i) {
if (i == (t - delta))cout << "(";
else cout << ")";
}
}