总结: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\)

posted @ 2024-09-15 20:28  GuTongXing  阅读(100)  评论(0)    收藏  举报