官方题解 | 巅峰赛#37
2026-08-18 10:10:36
发布于:浙江
巅峰赛37题解
本次题目的总体难度如下,各位选手可以借此评估一下自身的技术水平
| 题目编号 | 题目标题 | 难度 |
|---|---|---|
| T1 | 午枫的幸运名单 | 普及/提高- |
| T2 | 宝藏密码 | 普及/提高- |
| T3 | 午枫的宝藏 | 普及/提高- |
| T4 | 午枫的罗盘 | 普及/提高- |
| T5 | 午枫的航海日志 | 普及+/提高 |
| T6 | 午枫的密码本 | 普及+/提高 |
T1 午枫的幸运名单
题意简述
给定一份长度为 的名单以及午枫的名字 。
依次查看名单中的名字,如果找到与 相同的名字,则输出其所在位置(排名);如果遍历完整个名单仍未找到,则输出 -1。
解题思路
直接模拟查找即可。
读入午枫的名字后,依次读取名单中的每个名字,判断是否与目标名字相同。由于名单中的名字互不相同,因此最多只会匹配一次。
记录匹配到的位置,最后输出对应排名;若始终未匹配到,则输出 -1。
时间复杂度为 O(n)。
参考代码
#include <bits/stdc++.h>
using namespace std;
void solve() {
int n;
string target;
cin >> n >> target;
int answer = -1;
for (int i = 1; i <= n; i++) {
string name;
cin >> name;
if (name == target) {
answer = i;
}
}
cout << answer << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T--) {
solve();
}
return 0;
}
T2 宝藏密码
题意简述
给定 条形如 的方程,但 与输入的三个数 对应关系未知(共有 种可能的排列)。已知存在唯一的非负整数 同时满足所有方程(在合适的排列下),求这个 。
解题思路
由于每个方程只有 种可能的排列方式,我们可以枚举第一条方程的所有排列,对每种排列解出 (若该排列对应方程 有整数解且 ),然后验证这个 是否满足其余所有方程(每条方程存在一种排列使得等式成立)。由于解唯一,最多验证 次即可找到答案。复杂度 。
参考代码
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
vector<tuple<long long, long long, long long>> eq(n);
for (int i = 0; i < n; i++) {
long long u, v, w;
cin >> u >> v >> w;
eq[i] = {u, v, w};
}
auto [u0, v0, w0] = eq[0];
auto check = [&](long long x) -> bool {
for (auto [u, v, w] : eq) {
if (u * x + v == w) continue;
if (u * x + w == v) continue;
if (v * x + u == w) continue;
if (v * x + w == u) continue;
if (w * x + u == v) continue;
if (w * x + v == u) continue;
return false;
}
return true;
};
long long ans = -1;
if ((w0 - v0) % u0 == 0) {
long long x = (w0 - v0) / u0;
if (x >= 0 && check(x)) ans = x;
}
if ((v0 - w0) % u0 == 0) {
long long x = (v0 - w0) / u0;
if (x >= 0 && check(x)) ans = x;
}
if ((w0 - u0) % v0 == 0) {
long long x = (w0 - u0) / v0;
if (x >= 0 && check(x)) ans = x;
}
if ((u0 - w0) % v0 == 0) {
long long x = (u0 - w0) / v0;
if (x >= 0 && check(x)) ans = x;
}
if ((u0 - v0) % w0 == 0) {
long long x = (u0 - v0) / w0;
if (x >= 0 && check(x)) ans = x;
}
if ((v0 - u0) % w0 == 0) {
long long x = (v0 - u0) / w0;
if (x >= 0 && check(x)) ans = x;
}
cout << ans << '\n';
}
return 0;
}
T3 午枫的宝藏
题意简述
有 名水手(不包括船长),按顺位 到 继承。船长提出分配金币方案,全员(包括船长)投票。若半数及以上通过则执行,否则船长被处死,由第 顺位继承人接任并重新分配,以此类推。所有水手聪明、贪婪、互不信任,每个人在保证自己不被杀的前提下争取最大利益。求船长在保证自己存活的前提下分出去的最少金币总数,并按 输出,其中 是分配给第 顺位继承人的金币数。
解题思路
从少到多递推。记总人数为 (包括船长)。当只有船长一人()时,不需要分金币。对于 人情况,船长需要争取半数以上票(包括自己)。由于第 顺位继承人在下一轮会成为船长,他一定会反对当前船长的提案(因为反对后自己就能掌权)。因此船长只能拉拢后面的人。
通过归纳可以发现,最终分配方案为:第 顺位继承人得到 枚金币当且仅当 为偶数,否则得到 枚。即 当 为偶数, 当 为奇数。因此需要计算 ,共 项。该和为 。
参考代码
#include <bits/stdc++.h>
using namespace std;
const int MOD = 1e9 + 7;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T--) {
long long n;
cin >> n;
long long m = n / 2;
long long ans = m % MOD * ((m + 1) % MOD) % MOD;
cout << ans << '\n';
}
return 0;
}
T4 午枫的罗盘
题意简述
有 条刻度线 ,其中 为起始线, 由 逆时针旋转 得到。求有多少对 ()使得 。
解题思路
两条线垂直当且仅当它们的夹角为 的奇数倍。由于每次旋转 , 与 的夹角为 。 等价于 ,即 。因此 必须为偶数才有解,否则答案为 。
当 为偶数时,令 。条件化为 。由于 ,考虑将 按模 分组,每组内下标相差 的倍数。实际上, 与 垂直,与 也垂直,等等。统计所有满足 的对数即可。更简单的方法:将 条线按模 分成 组,每组有 或 条线。每组的贡献为该组内任取两条线的组合数?不对,垂直并不发生在同组内,而是发生在相隔 的倍数且差为奇数倍 的组之间?实际上 与 垂直当且仅当 是 的奇数倍。因此对于每组模 的同余类,它们内部相邻的线差恰好是 ,但垂直要求差为 。每个同余类内部,若按顺序排列,第 条线与第 条线垂直,与第 条线差 不垂直,与第 条线垂直,以此类推。因此每个同余类中,将线按顺序编号 ,则一对线 满足 为奇数即垂直。该同余类内的垂直对数为 。将所有同余类的贡献相加即可。
设 ,,则 个组有 条线, 个组有 条线。答案为:
参考代码
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T--) {
long long n, k;
cin >> n >> k;
if (k % 2 == 1) {
cout << "0\n";
continue;
}
long long d = k / 2;
long long a = n / d;
long long b = n % d;
auto f = [](long long x) {
return (x / 2) * ((x + 1) / 2);
};
long long ans = b * f(a + 1) + (d - b) * f(a);
cout << ans << '\n';
}
return 0;
}
T5 午枫的航海日志
题意简述
给定长度为 的序列 ,求有多少种不同的正整数对 ,使得序列中存在一个子序列(不连续)恰好为 。
解题思路
我们需要找到所有满足条件的 。枚举 和 不可行,考虑枚举子序列中第一个 和第二个 的位置。设第一个 在位置 ,第二个 在位置 (),并且它们之间至少有一个 。同时,在 之后需要存在一个 ()。由于 可以是任意正整数,实际上只要 之后存在任意一个正整数()即可,因为 可以取那个正整数的值。但注意 必须与 独立,且 只计一次。
更直接的做法:对于每个 ,考虑它出现的所有位置。我们需要两个 的位置中间有 ,且第二个 之后有正整数。如果存在这样的两个 ,那么所有出现在第二个 之后的正整数都可以作为 。因此对每个 ,贡献的 的数量等于第二个 之后的不同正整数的个数。为了去重,我们应当对每个 统计它能产生的 的集合,最后累加不同 的数量。
由于 ,可以枚举 。对于每个 ,找到第一个 位于两个 之间的可行方案。设 的出现位置为 。如果存在 和 使得 且区间 内包含至少一个 ,那么 之后的所有正整数都可以作为 。因此我们只需要记录每个 的“最早”满足条件的第二个 的位置,然后统计该位置之后的不同正整数个数。可以用后缀预处理每个位置之后的不同正整数的数量(注意只统计正整数,不包括 )。最后对每个 累加即可。
参考代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
int a[N], suf[N];
bool vis[N];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
vector<int> pos[N];
for (int i = 1; i <= n; i++) {
if (a[i] > 0) pos[a[i]].push_back(i);
}
// 后缀中不同正整数的数量
int cnt = 0;
memset(vis, 0, sizeof(vis));
for (int i = n; i >= 1; i--) {
if (a[i] > 0 && !vis[a[i]]) {
vis[a[i]] = true;
cnt++;
}
suf[i] = cnt;
}
long long ans = 0;
for (int p = 1; p <= 1000000; p++) {
if (pos[p].size() < 2) continue;
int best = n + 1;
for (int t = 0; t < (int)pos[p].size() - 1; t++) {
int i = pos[p][t], j = pos[p][t + 1];
// 检查 i 和 j 之间是否有 0
bool ok = false;
for (int k = i + 1; k < j; k++) {
if (a[k] == 0) {
ok = true;
break;
}
}
if (ok) {
best = min(best, j);
}
}
if (best <= n) {
ans += suf[best + 1];
}
}
cout << ans << '\n';
}
return 0;
}
T6 午枫的密码本
题意简述
给定字符串 和一个极大的整数 ,将 重复拼接 次得到 ,求 的最长严格递增子序列(LIS)的长度。
解题思路
当 (即 )时,可以从不同重复中分别取每个字母,从而得到所有不同字母,答案为 中不同字母的种类数。
当 时,暴力构造 重复 次,长度不超过 ,直接 DP 求 LIS 即可。
由于 以字符串形式给出,若其长度 或数值 则按第一种情况处理,否则转整数后暴力。
参考代码
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T--) {
string s, ks;
cin >> s >> ks;
set<char> st(s.begin(), s.end());
int m = st.size();
if (ks.size() > 2 || (ks.size() == 2 && (ks[0] > '2' || (ks[0] == '2' && ks[1] > '5')))) {
cout << m << '\n';
continue;
}
int k = stoi(ks);
string t;
for (int i = 0; i < k; i++) t += s;
int n = t.size();
vector<int> dp(n, 1);
int ans = 1;
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j++) {
if (t[j] < t[i]) {
dp[i] = max(dp[i], dp[j] + 1);
}
}
ans = max(ans, dp[i]);
}
cout << ans << '\n';
}
return 0;
}
全部评论 10
这次怎么有两道纯数学T3和T4。
1周前 来自 浙江
1T4纯数学,是6题之中最难的。
1周前 来自 浙江
1ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
1周前 来自 浙江
0ddddddddddddddddddddddddddddddddddddddd
1周前 来自 浙江
0d
1周前 来自 浙江
0d
1周前 来自 浙江
0d
1周前 来自 浙江
0d
1周前 来自 浙江
0d
1周前 来自 浙江
0d
1周前 来自 浙江
0



























有帮助,赞一个