巅峰赛 #37 题解 | 非官方
2026-08-18 20:40:10
发布于:香港
巅峰赛 #37 题解 | 非官方
本次题目猜测的总体难度如下,仅供参考:
| 题目编号 | 题目标题 | 难度 |
|---|---|---|
| T1 | 午枫的幸运名单 | |
| T2 | 宝藏密码 | |
| T3 | 午枫的宝藏 | |
| T4 | 午枫的罗盘 | |
| T5 | 午枫的航海日志 | |
| T6 | 午枫的密码本 |
T1. 午枫的幸运名单
题目大意
给一个正整数 和 个 字符串 ,并且给出一个 ,判断 是否在字符串中出现过,并且输出出现的位置的 ,如果没有出现则输出 -1。
解题思路
对于每一个输入的时候,直接判断输入的字符串是否等于 即可,但是如果用 的话,需要把答案记录下来,不能直接输出。
参考代码
#include <bits/stdc++.h>
#define int long long
#define PII pair<int, int>
#define fi first
#define se second
using namespace std;
const int N = 200010;
const int MOD = 998244353;
// const int MOD = 1e9 + 7;
void solve() {
int n; string p;
cin >> n >> p;
int ans = -1;
for(int i = 1; i <= n; i++) {
string x; cin >> x;
if(p == x) {
ans = i;
// 不能直接输出,不然输入会乱掉
}
}
cout << ans << endl;
}
signed main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int T = 1;
cin >> T;
while(T--) {
solve();
}
return 0;
}
单组测试样例时间复杂度:
T2. 宝藏密码
题目大意
给你 条公式,每一条公式有一个共同解 ,而方程为 ,其中 的位置可以调换。
解题思路
得出 所表示:
可以把所有 可能的 枚举出来。如果 ,则可以将这个答案压入一个 ,然后去重。由于答案为一,所以判断是否满足 即可。
参考代码
#include <bits/stdc++.h>
#define int long long
#define PII pair<int, int>
#define fi first
#define se second
using namespace std;
const int N = 200010;
const int MOD = 998244353;
// const int MOD = 1e9 + 7;
int a[N], b[N], c[N];
vector<int> s;
bool check(int x, int u, int v, int w) {
if(u * x + w == v || u * x + v == w || v * x + u == w || v * x + w == u || w * x + u == v || w * x + v == u) return true;
return false;
}
void solve1(int a, int b, int c) {
if((c - b) % a == 0) {
int x = (c - b) / a;
if(x >= 0) {
s.push_back(x);
}
}
}
void solve() {
int n; cin >> n;
s.clear();
for(int i = 1; i <= n; i++) {
cin >> a[i] >> b[i] >> c[i];
}
solve1(a[1], b[1], c[1]);
solve1(a[1], c[1], b[1]);
solve1(b[1], a[1], c[1]);
solve1(b[1], c[1], a[1]);
solve1(c[1], a[1], b[1]);
solve1(c[1], b[1], a[1]);
sort(s.begin(), s.end());
s.erase(unique(s.begin(), s.end()), s.end());
for(auto x : s) {
bool ok = true;
for(int i = 1; i <= n; i++) {
if(!check(x, a[i], b[i], c[i])) {
ok = false;
break;
}
}
if(ok) {
cout << x << endl;
return ;
}
}
cout << -1 << endl;
}
signed main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t; cin >> t;
while(t--) solve();
return 0;
}
单组测试样例时间复杂度:
T3. 午枫的宝藏
题目大意
有 个人。船长可以提出一个分配方案,如果投票超过半数则成功,否则船长被杀死。所有水手聪明、贪婪、互不信任,每个人在保证自己不被杀的前提下争取最大利益。求每个人能获取的金(不包括船长),且能保证自己活下来。压缩答案为:
解题思路
假设现在有 个人(不包括船长),那么他肯定投自己一票,票数过半,所以可以给自己利益最大化。
假设现在有 个人(不包括船长),那船长只需要令其中一个人同意,所以会给 号水手 个金,可以令 号水手举手。由于如果 号水手不同意, 号水手就会决定分配,而 号水手则一点金都拿不到,所以 号水手一定会同意。得出 数组:
接下来压缩答案,只有双数位的 才会对答案有贡献,所以如果 为偶数,则答案为 ;否则答案为 ,而公式则为 。
参考代码
#include <bits/stdc++.h>
#define int long long
#define PII pair<int, int>
#define fi first
#define se second
using namespace std;
const int N = 200010;
//const int MOD = 998244353;
const int MOD = 1e9 + 7;
void solve() {
int n; cin >> n;
int inv = 250000002;
if(n % 2 == 1) n -= 1;
cout << (n % MOD * (n + 2) % MOD) * inv % MOD << endl;
}
signed main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int T = 1;
cin >> T;
while(T--) {
solve();
}
return 0;
}
单组测试样例时间复杂度:
T4. 午枫的罗盘
题目大意
有 条线,相邻两条线之间的夹角为 ,求有多少对垂直的线。
解题思路
首先观察题目,如果 是奇数是不可能有任何垂直的线。且如果 ,则不可能有垂直的线。
和 垂直的第一条线为 。设 为 垂直的最后一条线, 为与 垂直的线的组数。则对与所有都有 。而还有多余的线(), 的区间有 条线; 的区间有 条线。则是每一组就有 ,提取 出来则是 ,项数为 。最后运用,求出答案即可。
参考代码
#include <bits/stdc++.h>
#define int long long
#define PII pair<int, int>
#define fi first
#define se second
using namespace std;
const int N = 200010;
const int MOD = 998244353;
// const int MOD = 1e9 + 7;
void solve() {
int n, k; cin >> n >> k;
if(k % 2 == 1) {
cout << 0 << endl;
return ;
} else if(n < k / 2) {
cout << 0 << endl;
return ;
}
int a = k / 2 + (n - k / 2) % k - 1;
int b = (n - k / 2) / k + 1;
int res = (a - k / 2 + 1) * b;
int cnt = max(0LL, (n - (a + 1)) / k);
res += (((b - 1) + (b - cnt)) * cnt / 2) * k;
cout << res << endl;
}
signed main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int T = 1;
cin >> T;
while(T--) {
solve();
}
return 0;
}
单组测试样例时间复杂度:
T5. 午枫的航海日志
题目大意
有 个数,有多少组数对 ,使得序列存在 。
解题思路
考虑这个问题可以先问一些问题:
- 对于每一个 ,应该选哪一个 ?当然是离 最近的那个 ,可以最大化后面 的个数。
- 对于每一个 ,应该选哪一个 ?当然是离 最近的那个 ,可以最大化后面 的个数。
我们可以用一个 数组,表示从当前位置到序列末尾有多少个不同数字个数,而且要记录下来每一个数字出现的位置。我们可以用 lower_bound 来查找后面的下标,再处理一下特殊情况就可以了。
参考代码
#include <bits/stdc++.h>
#define int long long
#define PII pair<int, int>
#define fi first
#define se second
using namespace std;
const int N = 1000010;
const int MOD = 998244353;
// const int MOD = 1e9 + 7;
int a[N], s[N];
map<int, int> mp, vis, vis1;
vector<int> v, ve[N], cnt;
void solve() {
int n; cin >> n;
mp.clear();
vis.clear();
v.clear();
cnt.clear();
vis1.clear();
for(int i = 0; i <= N; i++) ve[i].clear();
for(int i = 1; i <= n; i++) {
cin >> a[i];
if(a[i] == 0) v.push_back(i);
ve[a[i]].push_back(i);
if(vis.count(a[i]) == 0) cnt.push_back(a[i]);
vis[a[i]]++;
}
s[n] = 0;
for(int i = n - 1; i >= 1; i--) {
if(mp.count(a[i + 1])) s[i] = s[i + 1];
else if(a[i + 1] > 0) s[i] = s[i + 1] + 1;
else s[i] = s[i + 1];
mp[a[i + 1]]++;
}
int res = 0;
for(int i = 0; i < cnt.size(); i++) {
int num = cnt[i];
if(num == 0) continue;
int d = lower_bound(v.begin(), v.end(), ve[num][0]) - v.begin();
if(d == v.size()) continue;
int num1 = lower_bound(ve[num].begin(), ve[num].end(), v[d]) - ve[num].begin();
if(num1 == ve[num].size()) continue;
res += s[ve[num][num1]];
}
cout << res << endl;
}
signed main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int T = 1;
cin >> T;
while(T--) {
solve();
}
return 0;
}
单组测试样例时间复杂度:。
T6. 午枫的密码本
题目大意
给定一个字符串 ,将其拼接 次得出 ,求 的 值的最长上升子序列的长度。
解题思路
首先看到 的最大值为 ,所以显然不能直接暴力拼接,考虑优化。假设字符串 为 zyxwvutsrqponmlkjihgfedcba, 为 ,结果的值为 。由此得知,答案最大为 ,因为是严格上升子序列,而英文字母只有 个。所以 拼接 次就可以了。
怎么判断 是否大于 呢? 是字符串,无法直接判断。我们可以先看 的长度。如果大于 则一定是拼接 次。如果小于,直接换成 int 判断就行了。
最后,使用 求最长上升子序列即可。
参考代码
#include <bits/stdc++.h>
#define int long long
#define PII pair<int, int>
#define fi first
#define se second
using namespace std;
const int N = 200010;
const int MOD = 998244353;
// const int MOD = 1e9 + 7;
void solve() {
string s, k;
cin >> s >> k;
int l = 0;
if(k.size() > 2) l = 26;
else if(stoi(k) > 26) l = 26;
else l = stoi(k);
string d = s;
for(int i = 1; i < l; i++) {
s += d;
}
s = ' ' + s;
int dp[N];
int a[N];
for(int i = 0; i <= s.size() + 1; i++) {
dp[i] = a[i] = 0;
}
for(int i = 1; i <= s.size(); i++) {
dp[i] = 1;
a[i] = s[i] - 'a';
for(int j = 1; j < i; j++) {
if(a[j] < a[i]) {
dp[i] = max(dp[i], dp[j] + 1);
}
}
}
cout << *max_element(dp + 1, dp + s.size() + 1) << endl;
}
signed main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int T = 1;
cin >> T;
while(T--) {
solve();
}
return 0;
}
时间复杂度:,其中 为拼接后字符串的长度。
这里空空如也





















有帮助,赞一个