比赛题目共 \(2\) 套,其中初赛题 \(1\) 套,复赛 \(2\) 题。
比赛时间: \(10:50 - 12:00 a.m\)。
Part 0x01 过程-Process
\(8:30\,a.m.\) 做初赛题目;
\(10:40\,a.m.\) 拿到题目;
\(10:41\,a.m.\) 先写 \(\text{T2}\),发现做过,是背包;
\(10:50\,a.m.\) 写完 \(\text{T2}\);
\(10:51\,a.m.\) 开始写 \(\text{T1}\) ,发现是 \(\text{NP}\) 问题,差点懵掉。
\(10:52\,a.m.\) 发现 \(\text{T1}\) 的 \(n \leq 8\), 直接爆搜。
\(11:40\,a.m.\) 写完了 \(\text{T1}\)。
总分 \(= 100pts + 100pts = 200pts\)。
Part 0x02 初赛题目-Theory
Problem 1

注意到 nth_element() 可以解决这个问题,这个库函数用快排实现,时间复杂度 \(O(n)\)。
Problem 2

典型的迷惑题,可以这么考虑,先把 “优” 和 “良” 放在一堆, “及格” 和 “差” 放在一堆,花费 \(10 + 13 + 14 + 5 = 42\) 次操作。再把 “优”和 “良” 分成两堆, “及格” 和 “差” 分成两堆,花费 \(10 + 13 + 14 + 5 = 42\) 次操作, 共操作 \(42 + 42 = 84\) 次。
Problem 3

注意 “只关注每班派出的人数” 。
| 派出人数 | 方案数 |
|---|---|
| \(6, 0, 0\) | \(0\) 种(没有班的人数\(\leq 6\)) |
| \(5,1,0\) | \(1\) 种 |
| \(4,2,0\) | \(4\) 种 |
| \(3,3,0\) | \(3\) 种 |
| \(1, 2, 3\) | $ 3!=6$ 种 |
| \(2, 2, 2\) | \(1\) 种 |
| \(4, 1, 1\) | \(3\) 种 |
共 \(18\) 种,故选 \(\text{B}\)
Part 0x03 复赛题目-Problem
T1 哈密顿路径
好像是 \(\text{NP}\) 问题,差点懵掉,其实数据范围 \(1 \leq n \leq 8\) 已经说明可以暴力。
\(\mathfrak{Code\,Here}\)
// g++ "hami.cpp" -Wall -std=c++14 -o "hami"
// ./"hami"
#include <bits/stdc++.h>
using namespace std;
vector <int> G[100];
bool vis[100];
int n, m, ans = 0;
bool CheckHami()
{
for(int i = 1; i <= n; i++)
{
if(vis[i] != true)
{
return false;
}
}
return true;
}
void CountHami(int u)
{
if(CheckHami() == true)
{
ans++;
return;
}
for(auto v : G[u])
{
if(vis[v] != true)
{
// printf("%d ", v);
vis[v] = true;
CountHami(v);
vis[v] = false;
}
}
}
void ClearVector()
{
for(int i = 1; i <= 20; i++)
{
G[i].clear();
}
}
int main()
{
freopen("hami.in", "r", stdin);
freopen("hami.out", "w", stdout);
int T;
scanf("%d", &T);
while(T--)
{
ans = 0;
memset(vis, 0, sizeof(vis));
ClearVector();
scanf("%d %d", &n, &m);
for(int i = 1; i <= m; i++)
{
int u, v;
scanf("%d %d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
vis[1] = true;
CountHami(1);
vis[1] = false;
printf("%d\n", ans);
}
return 0;
}
时间复杂度 \(O(2^n)\)
T2 最大约数和
之前做过?
设 \(\sigma (i)\) 为除了 \(i\) 以外的 \(i\) 的因数和,那么题目可以视为,有 \(S\) 个物品,第 \(i\) 个物品重量
为 \(i\),价值为 \(\sigma (i)\),背包容量为 \(S\),求最大价值。
暴力的循环求出 \(\sigma (i)\),然后跑 \(01\) 背包即可。
\(\mathfrak{Code\,Here}\)
// g++ "fac.cpp" -Wall -std=c++14 -o "fac"
// ./"fac"
#include <bits/stdc++.h>
long long w[1010], v[1010];
long long dp[1010];
void GetDivisor(long long x)
{
long long ans = 0;
for(long long i = 1; i <= x-1; i++)
{
if(x % i == 0)
{
ans += i;
}
}
w[x] = x;
v[x] = ans;
}
int main()
{
freopen("fac.in", "r", stdin);
freopen("fac.out", "w", stdout);
long long n, W;
scanf("%lld", &n);
W = n;
for(long long i = 1; i <= n; i++)
{
GetDivisor(i);
}
for(long long i = 1; i <= n; i++)
{
for(long long j = W; j >= w[i]; j--)
{
dp[j] = std::max(dp[j], dp[j - w[i]] + v[i]);
}
}
printf("%lld", dp[W]);
return 0;
}
时间复杂度 \(O(S^2)\)
Part 0x04 总结-Summary
关于复赛
- 注意代码细节
- 存图应使用邻接表
- 当数据小的时候,可以使用
打表解决问题 - 考试注意文件名以及一定要测过了样例,没测样例基本 \(\textcolor{red}{0}\) 分
- 可以自己尝试造数据,需要使用
srand(time(0))和rand()函数 - 得到 \([l, r]\) 内的一个整数:
rand() % (r - l + 1) + l - 得到 \([l, r)\) 内的一个整数:
rand() % (r - l) + l - 可以多写个暴力来跑自己造出来的数据
- 值域过大时不宜用桶,\(10^8\) 个 \(int = 380\text{MB}\)
- 做题时思路略显粗糙,要加强对于知识点的练习和写模板
- \(\gcd\) 具有「可重复贡献性质」,区间 \(\gcd\) 和区间最大值一样需要使用 \(\text{ST}\) 表
- \(\gcd\) 本质上是对指数取 \(\min\)
- 对自己高要求:禁止考试有任意一道题目爆零.
- 检查文件名、
freopen、多组数据清空、输出换行等错误 - 搜索回溯是对称的
- 搜索的两种模式:一种是到该点时,该点信息已经处理完毕;一种是到该点时先处理该点信息再搜索。
- 得到所有数的约数之和的另类写法:考虑将 \(i\) 贡献到 \(i\) 的倍数上,相较于直接暴力的 \(O(n \sqrt{n})\),这个做法是 \(O(n log n)\) 的
关于初赛
- \(∨\) 代表或运算,即
|| - \(∧\) 代表与运算,即
&& - \(?\) 代表非运算,即
! - 文件型病毒传染的主要对象是
EXE和COM文件 - Linux下可执行文件没有后缀名
- 田忌赛马思想:
- 对手必胜,就用最小的马输给对手
- 对手必败,就用最小的马赢对手
- 我方必胜,就用最小的马赢对手
- 我方必败,就用最小的马输给对手
- 对拍 \(=\) 造数据程序 \(+\) 暴力程序 \(+\) 你的正解
- 如果不用补码思想,把 \(n\) 位二进制最高位当符号位,其他位正常储存,那么表示数字范围为 \([-2^n+1, 2^n-1]\),同时会引发 \(0 \neq -0\) 的 \(\text{BUG}\)
- 在 \(n\) 位补码中,数字范围为 \([-2^n, 2^n-1]\),同时 \(0 = -0\) ,加减法无需特判,同时也可以根据最高位判断是否是负数。
- 浮点数由尾数和阶码构成。
- 只给出前序遍历与后序遍历的情况下无法确认二叉树。
- 计算机四种存储器:硬盘、\(\text{RAM}\)、\(\text{Cache}\)、寄存器,速度逐渐变快,可用空间逐渐变小
- 二叉搜索树的每个节点内有数字,满足左子树都小于自己,右子树都大于自己
- \(n\) 个物品中有一件次品,已知这件次品轻一些,使用天平分三份称量;
- 组合数学从不同角度出发均可得到答案.
- \(100\) 以内的质数有 \(25\) 个
- 欧拉筛保证每个数只会被自己的最小质因子筛到一次,所以是 \(O(n)\) 的
- 每过一年星期数 \(+1\),闰年 \(+2\)
- 一行组合数加起来是 \(2\) 的次幂,也即 \(C(n, 0) + ... + C(n, n) = 2^n\)
- 判断 \(\text{T}\) 是否是 \(\text{S}\) 的子序列,可以直接 \(O(|S|)\) 的硬匹配,也可以预处理好 \(S\) 的
Pos[i][j]数组后 \(O(|T|)\) 地匹配 - 排列组合题要注意读题、耐心计算。
- 初赛强度取决于省份,现在初赛要求较高,一定认真对待初赛!!!!
- 分辨率的 \(4096*2160\) 指的是像素,一个像素可能是 \(32\) 位 \(24\) 位等
- 存储二叉树一般是左儿子是自己下标乘二,右儿子是自己下标 \(*2+1\)
- 排序的稳定性:比较关键字时,若关键字相同,不能改变他们的相对顺序就叫稳定
浙公网安备 33010602011771号