4.6日NOIP普及组模拟赛 总结
这一次普及组模拟赛我考了268分,还可以。
第一题:表达式括号匹配
题目链接
讲题视频链接
解题思路:
这道题目用双重循环可以暴力过。
但是最优解是栈——一种数据结构(是先进后出——
F
I
L
O
FILO
FILO 的数据结构)
方法:
我们遇到一个左括号,统计变量就加
1
1
1。
我们遇到一个右括号,统计变量就减
1
1
1。
如果最后这个变量等于
0
0
0,代表栈为空,也就意味着括号匹配成功。
但是,这种方法有一个问题,比如这个数据:
(
)
)
(
())(
())(
这个数据答案是
n
o
no
no,但是最后的变量为
0
0
0,答案是
y
e
s
yes
yes,那么就有问题了。
其实我们发现,只要某一个时间点右括号的数量大于左括号的数量,就是不匹配的。
也就是说,如果这个变量在某一个时刻小于
0
0
0了,那么就输出
n
o
no
no。
代码如下:
#include<bits/stdc++.h>
using namespace std;
int m;
int main()
{
char x;
x=getchar();
while(x!='@')
{
if(x=='(') m++;
if(x==')') m--;
if(m<0)
{
printf("NO");
return 0;
}
x=getchar();
}
if(m==0) printf("YES");
else printf("NO");
}
第二题:数的划分
题目链接
讲题视频链接
解题思路:
这道题目的方法是暴力。
直接递归就行了,数据可以卡过。
代码如下:
#include<bits/stdc++.h>
using namespace std;
int n,k,ans;
void dfs(int y,int x,int pre)
{
if(x==0)
{
if(y==0) ans++;
return;
}
for(int i=pre;i<=y/x;i++)
{
if(y-i<0) break;
dfs(y-i,x-1,i);
}
}
int main()
{
scanf("%d%d",&n,&k);
dfs(n,k,1);
printf("%d",ans);
}
至于更快的方法,是有的——动态规划、记忆化搜索等等。
第三题:小朋友的数字
题目链接
讲题视频链接
解题思路:
这道题的方法是动态规划。
其实我们要求的就是
1
1
1到
i
i
i之间的最大连续子段和。
设
f
i
f_i
fi表示以
i
i
i为结尾的最大子段和,
d
p
i
dp_i
dpi表示
1
1
1到
i
i
i之间的最大子段和。
则
f
i
=
m
a
x
(
f
i
−
1
+
a
i
,
a
i
)
f_i=max(f_{i-1}+a_i,a_i)
fi=max(fi−1+ai,ai)
d
p
i
=
m
a
x
(
d
p
i
−
1
,
f
i
)
dp_i=max(dp_{i-1},f_i)
dpi=max(dpi−1,fi)
那么我们只用递推求最大数就行了。
但是可能会爆
l
o
n
g
l
o
n
g
long long
longlong,所以要边模边做。