2021牛客寒假算法基础集训营1-B题
先直接上代码吧。
#include <cstdio>
#include <iostream>
#include <cmath>
using namespace std;
#define ll long long
int main()
{
int k;
//freopen("W:\\Programing\\testinput.txt","r",stdin);
//freopen("W:\\Programing\\outandin.txt","w",stdout);
while(scanf("%d",&k)!=EOF)
{
//printf("%d ",k);
if (k<=3)
{
if (k==0) printf("(\n");
if (k==1) printf("()\n");
if (k==2) printf("(()\n");
if (k==3) printf("()()\n");
continue;
}
int step=sqrt(k);
//printf("sqrt==%d ",step);
int reminder=(k-step*step);//reminder表示余数
int ans=reminder%2;//判断还需要偶数对还是奇数对括号;
for(int i=1;i<=step;i++) printf("(");//首先输出sqrt(k)个左括号;
int cnt=step+reminder/2+reminder%2;
for(int i=cnt;i>=1;i--)
{
if(i==2+ans+reminder/2) //输出reminder/2个(
{
for(int j=1;j<=reminder/2;j++,i--)
printf("(");
i++;//自己可以调试一下,看为什么要多这一步
}
else if (ans==1&&i==2) printf("(");
else printf(")");
}
printf("\n");
}
return 0;
}
个人思路:
首先我们知道,每个左括号都可以和它右边的右括号成功匹配;我们先反过来想,对于一个括号字符串(仅包含(
和)
的字符串)这个字符串所包含的匹配括号对数就可以很容易求出来:
匹配的括号对数=所有的(左括号 *它右边右括号的括号数量)的和;
那么 我们就先输出k的算术平方根个(
;接下来就是除了输出k的算术平方根个)
还有就是如何把k-(int)sqrt(K)*(int)sqrt(K)
对括号输出,我个人采用的方法是,首先,int cnt=step+reminder/2+reminder%2;
cnt表示还需要多少个括号,通过reminder/2
(整除!!!)计算出来在如果我用构造的括号字符串的最后两个)
和前面(
匹配的话,需要多少个(
。这里解释一下,为什么是最后两个)
?而不是三个、四个呢?因为如果用最后两个的话,要么可以在第sqrt(k)
个(
括号后面添加reminder/2
个(
完全匹配,要么会少一对括号不能达到k个括号,那么剩下的一对括号就可以通过在最后一个)
的前面添加一个(
实现。
下面举一个例子可能会更加清楚:
15==3*3+3*2
;
我们可以先构造九对匹配的括号((()))
;就这样,然后我们再把三个(
插入到合适的位置,
从倒数第2+reminder%2+reminder/2
个位置开始输出(
,而且15-3*3==6
为偶数,所以最终构造为
((()((())
.
第二个例子:
19==4*4+1*2+1
同理:先构造(((())))
已经把平方数的构造出来了,接着我们需要把1个(
插入到倒数第2+reminder%2+reminder/2
个位置,这样操作之后,还剩下一对括号,那么再倒数第一个)
前面插入一个(
就完成了我们的构造。
具体的构造步骤可以自己输入几个数据,小一点吧,太大了也不好,不容易看出来;
还有最后一个问题就是代码里面的i++
的问题了,简单说一下吧;当里里面的for
循环执行完毕的时候,已经对i进行了递减操作,但是外面的for
循环会再次执行一遍i–,这样,i就多减了一次,所以必须要i++;可以自己打个断点,观察一下哟;
还有就是,我的代码里面的` if (k<=3)
if (k<=3)
{
if (k==0) printf("(\n");
if (k==1) printf("()\n");
if (k==2) printf("(()\n");
if (k==3) printf("()()\n");
continue;
}
首先是要对k=0进行特判,因为题目要求非空,其次就是,当k=3的时候按照下面的代码输出的结果是不对的,k=2和k=3的输出结果是一样的,这个情况比较特殊,最直接的办法就是把k=3也给特判了。虽然这一题没有k=3这个数据(试过了,只特判0也可以过)。但还是加上吧,毕竟追求严谨还是好的;
如有错误,欢迎指正哟