2025牛客寒假算法基础集训营6

news/2025/2/11 19:15:04/文章来源:https://www.cnblogs.com/maburb/p/18710342

A. 复制鸡

题意:对于一个字符串,你每次可以选择其中任意一些位置,然后把每个位置上的字符复制一个到这个位置后面。现在给你一个操作过的字符串,求它的所有可能的原串的最小长度。

因为每个位置操作后是在后面添加一个相同的字符,那么我们可以把所有相同的区间当做一个字符。数有多少个这样的区间就行了。

点击查看代码
void solve() {int n;std::cin >> n;std::vector<int> a(n);for (int i = 0; i < n; ++ i) {std::cin >> a[i];}int ans = 1;for (int i = 1; i < n; ++ i) {ans += a[i] != a[i - 1];}std::cout << ans << "\n";
}

B. 好伙计猜拳

题意:给你\(n\)个二元组\((a, b)\),你可以花\(c2\)代价交换某个二元组的\(a, b\),或者删掉某个二元组。求最终让这个二元组序列的\(a\)\(b\)都非递减的最小代价。

比较简单的\(dp\)\(f[i][0/1]\)表示第\(i\)个位置时没有/有进行交换的最小代价。那么可以枚举上一个没有被删的位置在哪里,然后进行讨论就行。答案取值有点麻烦,可以加一个\(inf, inf\)的二元组到最后面,答案就是\(f[n + 1][0]\)

点击查看代码
void solve() {int n, c1, c2;std::cin >> n >> c1 >> c2;std::vector<std::pair<int, int>> a(n + 2);for (int i = 1; i <= n; ++ i) {std::cin >> a[i].first >> a[i].second;}a[n + 1] = {2e9, 2e9};const i64 inf = 1e18;std::vector f(n + 2, std::array<i64, 2>{inf, inf});f[0][0] = 0;for (int i = 1; i <= n + 1; ++ i) {for (int j = 0; j < i ; ++ j) {auto & [x, y] = a[i];auto & [c, d] = a[j];if (c <= x && d <= y) {f[i][0] = std::min(f[i][0], f[j][0] + (i64)(i - j - 1) * c1);}if (d <= x && c <= y) {f[i][0] = std::min(f[i][0], f[j][1] + (i64)(i - j - 1) * c1);}if (c <= y && d <= x) {f[i][1] = std::min(f[i][1], f[j][0] + (i64)(i - j - 1) * c1 + c2);}if (c <= x && d <= y) {f[i][1] = std::min(f[i][1], f[j][1] + (i64)(i - j - 1) * c1 + c2);}}}std::cout << f[n + 1][0] << "\n";
}

C. 数列之和

题意:在一个由偶数组成的无穷序列里,求所有长度大于\(2\)的区间和的第\(k\)大。

\(a_i = 2 \times i - 2\),一个区间\([i, j]\)的区间和为\(\frac{(j - i + 1)(a_i + a_j)}{2}\),代入得\(\frac{(j - i + 1)(2i - 2 + 2j - 2)}{2} = (j - i + 1)(i + j - 2)\)。可以通过打表发现除了大于\(2\)的所有\(2\)的幂,其它偶数都会出现。于是二分找到这个数即可。

点击查看代码
void solve() {//(j - i + 1)(i + j - 2)i64 k;std::cin >> k;auto check = [&](i64 x) -> i64 {i64 lg = std::__lg(x) - 1;return x / 2 - lg;};i64 l = 2, r = 3e18;while (l < r) {i64 mid = l + r >> 1ll;if (check(mid) >= k) {r = mid;} else {l = mid + 1;}}std::cout << l << "\n";
}

D. Viva La Vida(Fried-Chicken's Version)

待补。


E. 任造化落骰

待补。


F. 薪得体会

题意:\(n\)个二元组\((a, b)\),你可以将其重新排列,然后按顺序操作,开始工资为\(a_1\),如果前面的最大工资大于等于\(a_i\),则第\(i\)个的值为\(a_i + b_i\),否则为\(a_i\)。问最大工资是多少。

发现如果我们选最大的\(a_i\),那么其余的\(a_j + b_j\)都可以选,那么只剩下求有没有一种方式可以得到\(a_i + b_i\),如果\(a\)\(a_i\)的值有多个,那么就可以取到;如果只有一个,那么问题就变成比\(a\)\(a_i\)小的二元组里最大能不能是\(a_i\)。那么这提示我们按\(a\)从小到大处理。
按照\(a_i\)从小到大排序,然后按顺序遍历,如果有多个二元组\(a\)的值为\(a_i\),则所有\(a_j <= a_i\)\(a_j + b_j\)都可以取到,否则看前面小于\(a_i\)能得到的最大值能不能有\(a_i\),然后如果我们选\(a_i\),则前面的所有\(a_j < a_i\)\(a_j + b_j\)都可以取到。

点击查看代码
void solve() {int n;std::cin >> n;std::vector<std::pair<int, int>> a(n + 1);for (int i = 1; i <= n; ++ i) {std::cin >> a[i].first >> a[i].second;}std::sort(a.begin() + 1, a.end(), [&](std::pair<int, int> & a, std::pair<int, int> & b) {return a.first < b.first;});std::vector<int> pre(n + 1);for (int i = 1; i <= n; ++ i) {pre[i] = std::max(pre[i - 1], a[i].first + a[i].second);}int ans = 0;for (int i = 1; i <= n; ++ i) {int j = i;while (j <= n && a[i].first == a[j].first) {++ j;}-- j;if (j - i + 1 > 1) {ans = std::max(ans, pre[j]);} else if (ans >= a[i].first) {ans = std::max(ans, a[i].first + a[i].second);}ans = std::max(ans, pre[i - 1]);i = j;}ans = std::max(ans, a[n].first);std::cout << ans << "\n";
}

G. 目标是【L2】传说高手

待补。


H. 小鸡的排列构造

题意:要求构造一个排列,使得每个数在使用区间长度是偶数的区间或者区间长度是奇数的区间排序后位置改变。

这题可以猜结论,然后用\(I\)题代码验证。
下面是我的对拍代码。

点击查看代码
#define ls(u) tr[u].lson
#define rs(u) tr[u].rsonconst int N = 3e5 + 5;struct Node {int lson, rson;int sum;
}tr[N << 5];int tot = 0;
int root[N];void build(int &u, int l, int r) {u = ++ tot;if (l == r) {return;}int mid = l + r >> 1;build(ls(u), l, mid); build(rs(u), mid + 1, r);
}void modify(int &u, int v, int l, int r, int p, int x) {u = ++ tot;tr[u] = tr[v];tr[u].sum += x;if (l == r) {return;}int mid = l + r >> 1;if (p <= mid) {modify(ls(u), ls(v), l, mid, p, x);} else {modify(rs(u), rs(v), mid + 1, r, p, x);}
}int query(int u, int v, int l, int r, int p) {if (r <= p) {return tr[u].sum - tr[v].sum;}int mid = l + r >> 1;if (p <= mid) {return query(ls(u), ls(v), l, mid, p);} else {return query(ls(u), ls(v), l, mid, p) + query(rs(u), rs(v), mid + 1, r, p);}
}std::mt19937 gen(std::random_device{}());int rand(int l, int r) {std::uniform_int_distribution<int> dis(l, r);return dis(gen);
}void solve() {// int n, m;// std::cin >> n >> m;int n = 2000, m = 2000;std::vector<std::array<int, 3>> a(m);int t = rand(0, 1);// std::cerr << t << "\n";for (int i = 0; i < m; ++ i) {// int l, r, c;// std::cin >> l >> r >> c;int l = rand(1, n - 2), r = rand(l + 1, n);while ((r - l) % 2 != t) {r = rand(l + 1, n);}int c = rand(l, r);a[i] = {l, r, c};}std::vector<int> ans(n);for (int i = 0; i < n; ++ i) {ans[i] = n - i;}if ((a[0][1] - a[0][0] + 1) & 1) {for (int i = 1; i + 1 < n; i += 2) {std::swap(ans[i], ans[i + 1]);}}// for (int i = 0; i < n; ++ i) {// 	std::cout << ans[i] << " \n"[i == n - 1];// }tot = 0;build(root[0], 1, n);for (int i = 1; i <= n; ++ i) {modify(root[i], root[i - 1], 1, n, ans[i - 1], 1);}for (auto & [l, r, c] : a) {if (c == l + query(root[r], root[l - 1], 1, n, ans[c - 1]) - 1) {std::cout << "!!!" <<  l << " " << r << " " << c << "\n";}}
}

分类讨论一下,如果区间长度是偶数,则直接\(n, n - 1, ... , 2, 1\)倒着来就行了。这个还是容易想的,因为倒着来排序后区间会翻转。
否则如果是奇数,直接从第二个位置开始,两个两个交换就行了,直接猜的。

点击查看代码
void solve() {int n, m;std::cin >> n >> m;std::vector<std::array<int, 3>> a(m);for (int i = 0; i < m; ++ i) {int l, r, c;std::cin >> l >> r >> c;a[i] = {l, r, c};}std::vector<int> ans(n);for (int i = 0; i < n; ++ i) {ans[i] = n - i;}if ((a[0][1] - a[0][0] + 1) & 1) {for (int i = 1; i + 1 < n; i += 2) {std::swap(ans[i], ans[i + 1]);}}for (int i = 0; i < n; ++ i) {std::cout << ans[i] << " \n"[i == n - 1];}
}

I. 小鸡的排列构造的checker

题意:一个排列中,对于\(m\)个询问,求\([l, r]\)中的第\(c\)个在排序后位置有没有变。

没脑子想不出正解,直接上主席树了。
用主席树维护值域,然后对于每个查询,就是求\([l, r]\)里有多少个小于等于\(p_c\)的数。很板子。

点击查看代码
#define ls(u) tr[u].lson
#define rs(u) tr[u].rsonconst int N = 3e5 + 5;struct Node {int lson, rson;int sum;
}tr[N << 5];int tot = 0;
int root[N];void build(int &u, int l, int r) {u = ++ tot;if (l == r) {return;}int mid = l + r >> 1;build(ls(u), l, mid); build(rs(u), mid + 1, r);
}void modify(int &u, int v, int l, int r, int p, int x) {u = ++ tot;tr[u] = tr[v];tr[u].sum += x;if (l == r) {return;}int mid = l + r >> 1;if (p <= mid) {modify(ls(u), ls(v), l, mid, p, x);} else {modify(rs(u), rs(v), mid + 1, r, p, x);}
}int query(int u, int v, int l, int r, int p) {if (r <= p) {return tr[u].sum - tr[v].sum;}int mid = l + r >> 1;if (p <= mid) {return query(ls(u), ls(v), l, mid, p);} else {return query(ls(u), ls(v), l, mid, p) + query(rs(u), rs(v), mid + 1, r, p);}
}void solve() {int n, m;std::cin >> n >> m;std::vector<int> a(n + 1);for (int i = 1; i <= n; ++ i) {std::cin >> a[i];}tot = 0;build(root[0], 1, n);for (int i = 1; i <= n; ++ i) {modify(root[i], root[i - 1], 1, n, a[i], 1);}while (m -- ) {int l, r, c;std::cin >> l >> r >> c;std::cout << l + query(root[r], root[l - 1], 1, n, a[c]) - 1 << "\n";}
}

J. 铁刀磨成针

题意:有\(n\)回合,初始\(x\)攻击力,\(y\)个磨刀石。没回合可以选择磨不磨刀,磨刀会消耗一个磨刀石,然后x = x + 1,然后选择是否攻击,攻击会造成\(x\)伤害,x = x - 1。

如果我们先砍几刀再来磨刀,显然是不划算的,最差也是一边磨刀一边攻击。所以我们枚举前面某\(i\)回合刀并且不攻击,然后接下来回合分成两部分,一种是一边磨刀一边攻击,一种是磨不了刀,一直砍到结束,总伤害是一个等差序列,可以直接算。

点击查看代码
void solve() {i64 n, x, y;std::cin >> n >> x >> y;i64 ans = 0;for (int i = 0; i <= std::min(n, y); ++ i) {i64 m = n - i;i64 t = std::min(y - i, m);i64 sum = t * (x + i + 1);m -= t;i64 a = x + i;m = std::min(m, a);sum += m * (a + a - m + 1) / 2;ans = std::max(ans, sum);}std::cout << ans << "\n";
}

E. 鸡翻题

题意:\((x, x + 1)\)一组,\((x - 2, x - 1)\)一组,\((x + 2, x + 3)\)一组,依次类推。求有没有一组和是\(k\)

首先明显是一个奇数加一个偶数,所以\(k\)一定是奇数。既然\(k\)是奇数,那么\((x, x + 1)\)就固定了,检查有没有这样的一组就行,就是看每组奇偶性是不是和这个相同。

点击查看代码
void solve() {int x, y;std::cin >> x >> y;if (y % 2 == 0 || y / 2 % 2 != x % 2) {std::cout << "NO\n";} else {std::cout << "YES\n";}}

L. 变鸡器

题意:给你一个字符串,每次可以选择两个不一样的同时删去,最后能不能变成"\(CHICKEN\)"。

先检查字符够不够,然后检查CHICKEN是不是子序列。
然后减去对应的字符个数,那么问题就变成一个经典问题,也是上一场考过的知识点,有\(n\)个数,每次选两个数减一,问最多操作几次。如果\(max >= sum / 2\)则可以配\(sum - max\)对,否则可以配\(sum - sum\%2\)对。这里不求操作几次,而是求能不能全部匹配。

点击查看代码
void solve() {int n;std::cin >> n;std::string s;std::cin >> s;std::vector<int> cnt(26);for (auto & c : s) {++ cnt[c - 'A'];}std::string t = "CHICKEN";for (auto & c : t) {if ( -- cnt[c - 'A'] < 0) {std::cout << "NO\n";return;}}int j = 0;for (int i = 0; j < t.size() && i < n; ++ i) {if (s[i] == t[j]) {++ j;}}if (j != t.size()) {std::cout << "NO\n";return;}int sum = std::accumulate(cnt.begin(), cnt.end(), 0);int max = *std::max_element(cnt.begin(), cnt.end());if (sum % 2 == 1 || max > sum / 2) {std::cout << "NO\n";} else {std::cout << "YES\n";}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/882210.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

nodejs如何处理Token?一文深入浅出JWT签名验签

关于token的那些事儿,一文深入浅出JWT签名验签前端开发中关于Token的那些事儿:深入浅出JWT签名验签 作为前端也要懂JWT,首先了解两个概念JWK JWT JWK JWK(RSA JSON Web Key)是一种用于表示 RSA 公钥或私钥的 JSON 对象,JWK 是 JSON Web Token (JWT) 和 JSON Web Encrypti…

前端开发中关于Token的那些事儿:深入浅出JWT签名验签

关于token的那些事儿,一文深入浅出JWT签名验签前端开发中关于Token的那些事儿:深入浅出JWT签名验签 作为前端也要懂JWT,首先了解两个概念JWK JWT JWK JWK(RSA JSON Web Key)是一种用于表示 RSA 公钥或私钥的 JSON 对象,JWK 是 JSON Web Token (JWT) 和 JSON Web Encrypti…

Eddystone 与 iBeacon

Eddystone 与 iBeacon 蓝牙信标 (Beacons) 是一种单向通讯方式,所以一般的用途就是发送提醒。 Beacons 是指使用蓝牙4.0(BLE)技术发射信号的小设备。 目前存活的 Beacons 标准有两个,分别是 Google 的 Eddystone 和 Apple 的 iBeacon. Eddystone Eddystone 是谷歌基于 Beac…

OrangePi 5 编译 Android12 源码

OrangePi 5 编译 Android12 源码 材料准备 源码下载地址 Orange Pi - Orangepi官方教程编译环境 在以下环境的 Ubuntu 虚拟机编译通过,基于 VMware Workstation 17 Pro.系统版本:ubuntu-18.04.6-lts-desktop-amd64; CPU:i5-8400,为 VM 分配 4 核; 内存:8G RAM + 16G swap…

Maui 基础 - Preferences 存储和检索应用程序的首选项

Maui 基础 Preferences 是 .NET MAUI 提供的一个静态类,用于存储和检索应用程序的首选项(即设置或配置)。它提供了一种简单的键值对存储机制,可以跨平台使用。每个平台使用其本地的存储机制来实现这些功能,例如:iOS 使用 NSUserDefaults Android 使用 SharedPreferences …

另辟新径实现 Blazor/MAUI 本机交互(一)

本系列由浅入深逐个文件解析工作原理 目录:WebViewNativeApi.cs NativeApi.cs MainPage.xaml.cs 实战 串口 小票机 蓝牙WebViewNativeApi.cs WebViewNativeApi.cs 文件中的代码实现了一个 NativeBridge 类,用于在 .NET MAUI 应用程序中的 WebView 和本地代码之间进行通信。以下…

AI 如何重塑劳动力市场:基于 Claude 数据的深度分析

前言 本文翻译自 Anthropic 今天发布的 The Anthropic Economic Index ,经济指数报告,这份报告基于 Claude 的数据对目前的 AI 使用情况做了汇总。 引言 在未来的几年里,人工智能系统将对人们的工作方式产生重大影响。因此,我们推出了 Anthropic Economic Index,这是一个旨…

Nacos Python SDK 强势来袭,动态管理大模型 Prompt!

Nacos 从 0.8.0 版本开始就一直参与 Python 生态建设,努力作为 Python 生态中分布式微服务发现和配置管理的解决方案一直往前演进。目前随着 AI 领域的发展,Nacos 社区的 Python 开发者用户越来越多,因此这次我们迭代了 Python 的 GA 稳定版本,对不少历史问题做了修复以及易…

踩坑记录-二分搜索的不同情况

二分搜索的不同情况 二分搜索可以用来查找满足条件的值,但是满足条件的值可能只有1个,也可能有多个。比如查找1的索引,对于【1,1,2,2】来说,就有2个。一般要求的就是:满足条件最大值/满足条件最小值。 二分搜索详细介绍可以参考:https://programmercarl.com/0704.二分…

《ESP32-S3使用指南—IDF版 V1.6》第五章 搭建开发环境

第五章 搭建开发环境 1)实验平台:正点原子DNESP32S3开发板 2)章节摘自【正点原子】ESP32-S3使用指南—IDF版 V1.6 3)购买链接:https://detail.tmall.com/item.htm?&id=768499342659 4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/esp32/AT…

内测之家介绍

内测之家:助力应用开发与迭代的专业平台内测之家是一款功能强大且全面的应用内测与管理平台,专为 iOS 和 Android 开发者打造,旨在为他们提供便捷高效、安全可靠的一站式服务。无论是从资源安全到传输安全,还是从数据保护到应用管理、统计分析,内测之家都展现出卓越的能力…

如何用好 AI 编码工具,让通义灵码帮你做更多工作

通义灵码,是阿里云与通义实验室联合打造的智能编码辅助工具,提供行级/函数级实时续写、自然语言生成代码、单元测试生成、代码优化、注释生成、代码解释、研发智能问答、异常报错排查等能力,提供代码智能生成、研发智能问答能力。通义灵码,是阿里云与通义实验室联合打造的智…