总结:1037 - CSP 2021 提高级第一轮

我的提交记录与结果

一、 单项选择题

  1. 以比较为基本运算,对于 \(2n\) 个数,同时找到最大值和最小值,最坏情况下需要的最小的比较次数为( )。
    \(\texttt A\). 4n-2
    \(\texttt B\). 3n+1
    \(\color{#5eb95e}\texttt{C}\). 3n-2
    \(\color{#e74c3c}\texttt D\). 2n+1

    【解析】:

    首先先将原数组两两分组。每组求一个最大,一个最小。使用 \(n\) 次。

    这样化成 \(n\) 组最大和最小。此时直接最大与最大进行比较,最小与最小进行比较,使用 \(2n-2\) 次。

    总共有 \(n+2n-2=3n-2\) 次。

    【反思】:

    思维不够。

  2. G 是一个非连通简单无向图(没有自环和重边),共有 36 条边,则该图至少有( )个点。
    \(\texttt A\). 8
    \(\color{#e74c3c}\texttt B\). 9
    \(\color{#5eb95e}\texttt C\). 10
    \(\texttt D\). 11

    【反思】:

    审题不认真:

    G 是一个非连通简单无向图(没有自环和重边),共有 36 条边,则该图至少有( )个点。

  3. 前序遍历和中序遍历相同的二叉树为且仅为( )。
    \(\texttt A\). 只有 1 个点的二叉树
    \(\color{#e74c3c}\texttt B\). 根结点没有左子树的二叉树
    \(\texttt C\). 非叶子结点只有左子树的二叉树
    \(\color{#5eb95e}\texttt D\). 非叶子结点只有右子树的二叉树

    【反思】:

    不要只考虑根的情况,在遍历中,所有部分都是根。

二、阅读程序

(一)

#include <iostream>
#include <cmath>
using namespace std;
const double r = acos(0.5);
int a1, b1, c1, d1;
int a2, b2, c2, d2;
inline int sq(const int x) { return x * x; }
inline int cu(const int x) { return x * x * x; }
int main()
{
cout.flags(ios::fixed);
cout.precision(4);
cin >> a1 >> b1 >> c1 >> d1;
cin >> a2 >> b2 >> c2 >> d2;
int t = sq(a1 - a2) + sq(b1 - b2) + sq(c1 - c2);
if (t <= sq(d2 - d1)) cout << cu(min(d1, d2)) * r * 4;
else if (t >= sq(d2 + d1)) cout << 0;
else {
double x = d1 - (sq(d1) - sq(d2) + t) / sqrt(t) / 2;
double y = d2 - (sq(d2) - sq(d1) + t) / sqrt(t) / 2;
cout << (x * x * (3 * d1 - x) + y * y * (3 * d2 - y)) * r;
}
cout << endl;
return 0;
}

分析程序

首先这个程序的第 \(5\) 行的地方,有一个 \(\arccos(0.5)\),这个有一点常识就知道 \(cos(60^{\circ})=0.5\),所以这个是 \(\arccos(0.5)=60^{\circ}=60\times\pi\div 180=\displaystyle \frac\pi3\)

而球的体积公式为 \(\displaystyle\frac34 \pi r^3\)

所以这个应该跟球的体积有关系。

后面 t = sq(a1 - a2) + sq(b1 - b2) + sq(c1 - c2) 可以推测出来是球心距,而 t <= sq(d2 - d1) 是判断两个球是否包含,t >= sq(d2 + d1) 是判断是否相交,所以推测这个是两个球的体积并

这个可以参考这篇文章:球的体积并(计算几何+球缺)

然后就没有然后了。

#include <algorithm>
#include <iostream>
using namespace std;
int n, a[1005];
struct Node
{
int h, j, m, w;
Node(const int _h, const int _j, const int _m, const int _w):
h(_h), j(_j), m(_m), w(_w)
{ }
Node operator+(const Node &o) const
{
return Node(
max(h, w + o.h),
max(max(j, o.j), m + o.h),
max(m + o.w, o.m),
w + o.w);
}
};
Node solve1(int h, int m)
{
if (h > m)
return Node(-1, -1, -1, -1);
if (h == m)
return Node(max(a[h], 0), max(a[h], 0), max(a[h], 0), a[h]);
int j = (h + m) >> 1;
return solve1(h, j) + solve1(j + 1, m);
}
int solve2(int h, int m)
{
if (h > m)
return -1;
if (h == m)
return max(a[h], 0);
int j = (h + m) >> 1;
int wh = 0, wm = 0;
int wht = 0, wmt = 0;
for (int i = j; i >= h; i--) {
wht += a[i];
wh = max(wh, wht);
}
for (int i = j + 1; i <= m; i++) {
wmt += a[i];
wm = max(wm, wmt);
}
return max(max(solve2(h, j), solve2(j + 1, m)), wh + wm);
}
int main()
{
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
cout << solve1(1, n).j << endl;
cout << solve2(1, n) << endl;
return 0;
}

代码分析

这个稍微写了线段树的人就知道是一个最大字段和问题。现在来重点考一下我错了的题。

错题分析

25.solve1(1, n) 的时间复杂度为( )。
\(\texttt A\). \(\Theta(\log n)\)
\(\color{#5eb95e}\texttt B\). \(\Theta(n)\)
\(\color{#e74c3c}\texttt C\). \(\Theta(n \log n)\)
\(\texttt D\). \(\Theta(n^2)\)

这个可以分析一下:\(T(n)=2\cdot T(n/2)=n\)

本文作者:辜铜星

本文链接:https://www.cnblogs.com/gutongxing/p/18415591

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   辜铜星  阅读(31)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起