2025牛客寒假算法基础集训营6
A
栈秒了
CODE
void solve()
{
int n = 0;
std::cin >> n;
std::stack<int> a;
for (int i = 0; i < n; i++) {
int x = 0;
std::cin >> x;
if (a.empty() || a.top() != x) {
a.push(x);
}
}
std::cout << a.size() << '\n';
}
B
题目大意
给定两个序列
- 花费代价
同时删去 和 。 - 花费代价
交换 和 。
问需要花费多少代价,才能使两个序列同时是不降的。
解题思路
注意到数据量不大,所以可以用
设
假设
于是我们就得到了一个
CODE
void solve()
{
int n = 0, c1 = 0, c2 = 0;
std::cin >> n >> c1 >> c2;
std::vector a(n + 1, 0ll), b(n + 1, 0ll);
for (int i = 1; i <= n; i++) {
std::cin >> a[i] >> b[i];
}
a.push_back(Inf), b.push_back(Inf);
// dp[i][0/1] 前 i 条记录不变第 i 条 / 反转第 i 条 所需要的最小代价
std::vector dp(n + 2, std::vector(2, Inf));
dp[0] = { 0, 0 };
for (int i = 1; i <= n + 1; i++) {
for (int j = 0; j < i; j++) {
if (a[j] <= a[i] && b[j] <= b[i]) {
dp[i][0] = std::min(dp[i][0], dp[j][0] + 1ll * (i - j - 1) * c1);
dp[i][1] = std::min(dp[i][1], dp[j][1] + 1ll * (i - j - 1) * c1 + c2);
}
if (a[j] <= b[i] && b[j] <= a[i]) {
dp[i][1] = std::min(dp[i][1], dp[j][0] + 1ll * (i - j - 1) * c1 + c2);
dp[i][0] = std::min(dp[i][0], dp[j][1] + 1ll * (i - j - 1) * c1);
}
}
}
std::cout << dp[n + 1][0] << '\n';
}
C
题目大意
序列
解题思路
打表后可以发现序列是在所有的偶数中,除去除了 2 以外的 2 的次幂得到的序列。知道这点后就能做了。
CODE
void solve()
{
i64 k = 0;
std::cin >> k;
k--;
if (k == 0) {
std::cout << 2 << '\n';
return;
}
int l = 1, r = 62;
while (l <= r) {
int m = l + r >> 1;
if ((1ull << m) < k + m + 1ll) {
l = m + 1;
}
else {
r = m - 1;
}
}
// std::cout << r << ' ' << l << '\n';
k -= (1ull << r) - r - 1;
std::cout << (1ull << l) + (k << 1) << '\n';
}
F
题目大意
有
解题思路
直接排序,和小的放前面。我们从前往后遍历更新目前拥有的价值
CODE
void solve()
{
int n = 0;
std::cin >> n;
std::vector a(n, std::array<int, 2>{ 0, 0 });
for (auto &[x, y] : a) {
std::cin >> x >> y;
}
std::sort(a.begin(), a.end(), [&](auto &u, auto &v) {
if (u[0] + u[1] == v[0] + v[1]) {
return u[0] < v[0];
}
else {
return u[0] + u[1] < v[0] + v[1];
}
});
int mx = a[0][0];
for (int i = 1; i < n; i++) {
if (mx >= a[i][0]) {
mx = std::max(mx, a[i][0] + a[i][1]);
}
else {
mx = std::max(mx, a[i][0]);
mx = std::max(mx, a[i - 1][0] + a[i - 1][1]);
}
}
std::cout << mx << '\n';
return;
}
H
题目大意
构造一个长度为
解题思路
当所有区间的长度都是偶数时,直接输出字典序最大的排列就好了。此时对任意一个区间进行排序区间内所有的数的位置都会改变。
当区间长度都是奇数时,上述构造方法就不成立,因为区间最中间一个数的位置不会变。
考虑最小的三个数的区间,此时只有两种构造方法:大小中(312
)和中大小(231
)。于是我们只用所有的长度为 3 的区间满足两种构造方法只易就好了。如果用图来表示构造出来的序列,形状应该是下降的折线。比如:
- 长度为 4 的排列:
4231
- 长度为 5 的排列:
53412
- 长度为 6 的排列:
645231
- 长度为 7 的排列:
7563412
CODE
void solve()
{
int n = 0, m = 0;
std::cin >> n >> m;
std::vector s(m, std::array<int, 3>{});
for (auto &[l, r, c] : s) {
std::cin >> l >> r >> c;
}
if ((s[0][1] - s[0][0]) % 2 == 1) {
for (int i = n; i >= 1; i--) {
std::cout << i << " \n"[i == 1];
}
}
else {
std::cout << n << ' ';
for (int i = n - 1; i >= 2; i -= 2) {
std::cout << i - 1 << ' ' << i << ' ';
}
if (n % 2 == 0) {
std::cout << 1 << ' ';
}
std::cout << '\n';
}
return;
}
I
题目大意
给定一个排列,有个形如
解题思路
想要知道对一个区间内的数排序后某一个数的位置,我们只需要知道区间里有多少个数是小于它的就好了。于是我们将询问排序,位置
CODE
class BIT {
private:
int n;
std::vector<int> tr;
int lowbit(int x) {
return x & -x;
}
int sum(int pos) {
int res = 0;
for (int i = pos; i > 0; i -= lowbit(i)) {
res += tr[i];
}
return res;
}
public:
BIT(int _n) {
n = _n;
tr.assign(n + 1, 0);
}
void add(int pos) {
for (int i = pos; i <= n; i += lowbit(i)) {
tr[i]++;
}
}
int sum(int l, int r) {
return sum(r) - sum(l - 1);
}
};
void solve()
{
int n = 0, m = 0;
std::cin >> n >> m;
std::vector p(n + 1, 0), pos(n + 1, 0);
for (int i = 1; i <= n; i++) {
std::cin >> p[i];
pos[p[i]] = i;
}
std::vector q(n + 1, std::vector<std::array<int, 3>>());
for (int i = 0; i < m; i++) {
int l = 0, r = 0, c = 0;
std::cin >> l >> r >> c;
q[p[c]].push_back({ i, l, r });
}
std::vector ans(m, 0);
std::vector vis(n + 1, false);
BIT t(n);
for (int i = 1; i <= n; i++) {
for (auto &[id, l, r] : q[i]) {
ans[id] = l + t.sum(l, r);
}
t.add(pos[i]);
}
for (auto &i : ans) {
std::cout << i << '\n';
}
return;
}
J
题目大意
- 攻击力增 1
- 以当前攻击力攻击,并造成等同于当前攻击力的伤害。攻击后减少一点攻击力,攻击力为 0 时不能攻击。
你的初始攻击力是
解题思路
首先肯定是要尽量把
在攻击力降为 0 之前有三个阶段
- 只增加攻击力不攻击
- 即增加攻击力又攻击
- 只攻击
在
CODE
void solve()
{
int n = 0, x = 0, y = 0;
std::cin >> n >> x >> y;
int ans = 0;
// 枚举前面只磨刀的轮数
for (int i = 0; i <= std::min(n, y); i++) {
int d0 = x + i; // 初始伤害
int con = std::min(n, y) - i; // 边磨刀边攻击的轮数
int att = std::min(n - con - i, d0); // 只攻击的轮数
ans = std::max(ans, (d0 + 1) * con + (2 * d0 - att + 1) * att / 2);
}
std::cout << ans << '\n';
return;
}
K
判断
CODE
void solve()
{
int x = 0, y = 0;
std::cin >> x >> y;
x += x + 1;
if (y == 0 || (x + y) % 2 == 0) {
std::cout << "YES\n";
}
else {
std::cout << "NO\n";
}
}
L
首先看能不能从原串中选出一个子序列使得子序列组成的串等于目标串,有的话就剔除找的的子序列,然后统计剩余的串中各个字母分别出现了多少次。如果出现次数最多的字母出现的次数超过了一半,直接判无解,否则只有当剩余串的串长是偶数是才判有解。
CODE
bool solve()
{
int n = 0;
std::string s;
std::cin >> n >> s;
std::vector cnt(26, 0);
int p = 0;
for (auto &c : s) {
cnt[c - 'A']++;
if (p < T.size() && c == T[p]) {
p++;
}
}
if (p != T.size()) {
return false;
}
for (auto &c : T) {
cnt[c - 'A']--;
}
std::sort(cnt.begin(), cnt.end());
n -= T.size();
if (cnt.back() * 2 > n) {
return false;
}
else {
return n % 2 == 0;
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话