Codeforces Round 894 (Div. 3) A-F题解
A. Gift Carpet
题意
最近,特马和维卡庆祝了家庭日。他们的朋友 Arina 送给他们一块地毯,这块地毯可以用拉丁文小写字母的
维卡还没看过礼物,但特马知道她喜欢什么样的地毯。如果维卡能在地毯上读出自己的名字,她一定会喜欢的。她从左到右逐列阅读,并从当前列中选择一个或零个字母。
从形式上看,如果可以从左到右依次选择四个不同的列,使第一列包含 "v",第二列包含 "i",第三列包含 "k",第四列包含 "a",那么女孩就会喜欢这块地毯。
帮助 Tema 提前了解 Vika 是否会喜欢 Arina 的礼物。
题解
将每列的字符找出,使用string
保存,然后从左到右通过string.find()
依次寻找vika
。
代码
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
#define SZ(x) (int)(x.size())
#define FOR(i,x,y) for (int i = (x),_##i = (y);i < _##i;i++)
#define FORD(i,x,y) for (int i = (x),_##i = (y);i > _##i;i--)
inline void GIL();
int main() {
ios::sync_with_stdio(false);cin.tie(nullptr);
int t = 1;
cin >> t;
FOR (id, 1, t + 1) { GIL(); }
return 0;
}
inline void GIL() {
int n, m;
cin >> n >> m;
vector<string> v(m, ""); // 用来存储列字符串,一共m列。
int ans = 0;
string t = "vika";
FOR (i,0, n) { // i:[0, n - 1]
string s;
cin >> s;
FOR (j, 0, m) { // j:[0, m - 1]
v[j] += s[j]; // 第j个字符放入第j列中。
}
}
int idx = 0;
FOR (i, 0, m) { // i:[0, m - 1]
if (v[i].find(t[idx]) != v[i].npos) idx++;
if (idx == 4) break; // 由于字符串'vika'的最大下标为3,当idx为4时就退出。
}
cout << (idx == 4 ? "YES\n" : "NO\n"); // 判断是否依次全部找到。
}
B. Sequence Game
题意
特马和维卡正在玩下面的游戏。
首先,维卡想出一个长度为
- 首先,她写下
。 - 然后,她只写下那些
( ),使得 。这个序列的长度记为 。
例如,从序列
然后,她把写有序列
特马认为在这样的游戏中获胜的可能性很小,但他仍然希望至少找到一个序列
注意,您输出的序列长度不应超过输入序列长度的两倍。
题解
首先
-
如果
,那么将 放入 中。当前
的最后一个元素一定是 ,那么将 放入 后,一定能从 中得到 ,因为 。例如:
按照上面的规则,可以得到
,而这个 是可以再推出 的。 -
否则,即
,将两个 放入 中。两个
放入 后, 的后三个元素依次为 ,由于 ,满足 的就只有 ,并得到一个 。例如:
按上面的规则,可以得到
,同样也可以再推出 的。
按上面的规则得到的
代码
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
#define SZ(x) (int)(x.size())
#define FOR(i,x,y) for (int i = (x),_##i = (y);i < _##i;i++)
#define FORD(i,x,y) for (int i = (x),_##i = (y);i > _##i;i--)
inline void GIL();
int main() {
ios::sync_with_stdio(false);cin.tie(nullptr);
int t = 1;
cin >> t;
FOR (id, 1, t + 1) { GIL(); }
return 0;
}
inline void GIL() {
int n;
cin >> n;
vector<int> v(n); // 用来存放b数组
FOR (i, 0, n) cin >> v[i];
vector<int> ans; // 用来存放a数组
ans.push_back(v[0]); // 首先b[0]一定在a中
FOR (i, 1, n) { // i:[1, n - 1]
if (v[i] >= v[i - 1]) ans.push_back(v[i]); // 只需要放一个
else { // 需要放两个
ans.push_back(v[i]);
ans.push_back(v[i]);
}
}
cout << SZ(ans) << "\n";
FOR (i, 0, SZ(ans)) {
cout << ans[i] << " \n"[i == SZ(ans) - 1];
}
}
C. Flower City Fence
题意
安雅住在花城。根据市长的命令,她必须为自己修建一道围墙。
围栏由
安雅开始好奇她的栅栏是否与对角线对称。换句话说,如果她按照相同的顺序水平铺设所有木板,是否会得到相同的栅栏。
例如,对于
左边的栅栏是
但是对于
左边的栅栏是
帮助安雅判断她的栅栏是否对称。
题解
我们可以进行模拟。先得到一列一列摆放好的木板,再尝试在现在摆放好的木板上一行一行地再次覆盖原来的木板。以上面的两张图片为例,将右边的图片放到左边的图片上,看右边的图片是否能与左边的图片完全重合。如果能,就是对称的;否则就不是对称的。
那如何实现模拟上诉过程呢?
设
我们尝试将右边的图片中的木板,从下往上,一个一个地平移到左边图片中。
那么对于右边的从下往上的第
这里
,里面的 表示下标为 ,而 表示下标 到下标 的最小值 。
所以要满足对称,那么
代码
#include <iostream>
#include <vector>
using namespace std;
#define FOR(i,x,y) for (int i = (x),_##i = (y);i < _##i;i++)
#define FORD(i,x,y) for (int i = (x),_##i = (y);i > _##i;i--)
inline void GIL();
int main() {
ios::sync_with_stdio(false);cin.tie(nullptr);
int t = 1;
cin >> t;
FOR (id, 1, t + 1) { GIL(); }
return 0;
}
inline void GIL() {
int n;
cin >> n;
vector<int> v(n + 1, 0); // a数组
bool ans = 1; // 记录答案,1表示对称,0表示不对称。
FOR (i, 1, n + 1) {
cin >> v[i];
if (v[i] > n) { // a[i] > n,一定不满足对称。
ans = 0;
}
}
if (!ans) {
cout << "NO\n";
return;
}
FOR (i, 1, n + 1) {
if (v[v[i]] < i) { // 平移,需要满足a[a[i]] >= i
ans = 0;
break;
}
}
cout << (ans ? "YES\n" : "NO\n");
}
D. Ice Cream Balls
题意
特马决定提高自己制作冰淇淋的技能。他已经学会了如何恰好用两个球把冰淇淋做成圆锥形。
在痴迷冰淇淋之前,特马对数学很感兴趣。因此,他很想知道,要制作恰好
有很多可能的冰淇淋口味:
如果组成冰淇淋的两个球的味道的集合是不同的,则这两个冰淇淋被认为是不同的。例如,
例如,有以下冰淇淋球
注意,特马不需要同时制作所有的甜筒冰淇淋。这意味着他可以独立制作冰淇淋甜筒。另外,为了在某个
请帮助特马回答这个问题。可以证明答案总是存在的。
题解
对于不同口味的
代码
#include <algorithm>
#include <iostream>
using namespace std;
using ll = long long;
using i128 = __int128_t;
#define FOR(i,x,y) for (int i = (x),_##i = (y);i < _##i;i++)
#define FORD(i,x,y) for (int i = (x),_##i = (y);i > _##i;i--)
inline void GIL();
int main() {
ios::sync_with_stdio(false);cin.tie(nullptr);
int t = 1;
cin >> t;
FOR (id, 1, t + 1) { GIL(); }
return 0;
}
inline void GIL() {
ll n;
cin >> n;
ll l = 2, r = 1e18;
auto check = [&] (ll mid) {
i128 t = mid; // 防爆longlong
return (t * (t - 1) / 2 >= n); // C_{t}^2 >= n
};
while (l < r) { // 二分得到x,使得C_x^2 >= n
ll mid = (l + r) >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
ll all = l * (l - 1) / 2; // 计算C_X^2
if (all > n) {
all = n - (l - 1) * (l - 2) / 2; // left = n - C_{x-1}^2
l += all - 1; // 这个-1是为了得到答案,按我的想法,应该是加all。
}
cout << l << "\n";
}
E. Kolya and Movie Theatre
题意
最近,科里亚发现他所在的城市即将开一家新的电影院,每天都会放映一部新电影,连续放映
然而,Kolya 没有去电影院看电影的时间越长,下一部电影的娱乐价值的下降幅度就越大。这种下降相当于
例如,如果
不幸的是,科里亚只有时间去看最多
题解
我们可以发现,假设最后一部电影是在
那么我们可以贪心,遍历天数,对于每一天
那么,我们想让最大娱乐值最大,那么
代码
#include <algorithm>
#include <iostream>
#include <queue>
#include <utility>
#include <vector>
using namespace std;
using ll = long long;
#define FOR(i,x,y) for (int i = (x),_##i = (y);i < _##i;i++)
#define FORD(i,x,y) for (int i = (x),_##i = (y);i > _##i;i--)
inline void GIL();
int main() {
ios::sync_with_stdio(false);cin.tie(nullptr);
int t = 1;
cin >> t;
FOR (id, 1, t + 1) { GIL(); }
return 0;
}
struct cmp {
bool operator () (int &a, int & b) {
return b < a; // 用来确保最小值在堆顶部。
}
};
inline void GIL() {
int n, m;
ll d;
cin >> n >> m >> d;
vector<ll> v(n);
priority_queue<int, vector<int>, cmp> pq; // 最小堆
ll ans = 0, sum = 0; // 最后的答案ans,还有sum
FOR (i, 0, n) { // i:[0,n-1]
cin>> v[i];
if (v[i] <= 0) continue; // 忽略小于0的值
if (pq.empty() || SZ(pq) < m) { // 如果还不够m部电影,就一直看
sum += v[i];
pq.push(v[i]);
} else if (SZ(pq) == m && v[i] > pq.top()) { // 已经看了m部电影,那么可以去掉最小的值,放入较大的值
sum += v[i] - pq.top();
pq.pop(); // 去掉最小的
pq.push(v[i]); // 放入比较大的
}
ans = max(ans, sum - (i + 1) * d); // 更新一下答案。
}
cout << ans << "\n";
}
F. Magic Will Save the World
题意
黑暗力量的传送门在两个世界的交界处打开了,现在整个世界都面临着可怕的威胁。为了关闭传送门,拯救世界,你需要打败一个又一个从传送门中出现的
只有女魔法师维卡才能胜任。她拥有两种魔法能力--水魔法和火魔法。在一秒钟内,维卡可以产生
每个从传送门中出现的
维卡可以瞬间创造和施放法术。只要有足够的法力,维卡每秒可以施放无限多个法术。
女巫想要尽快拯救世界,请告诉她需要多少时间。
题解
由于要求最小时间,表示可以二分找到这个最小时间。
那么,对于一个时间
首先,我们拥有两种法术,那么,对于一种法术而言,其值为
然后再判断另一种法术是否能打败剩下的怪物即可。
代码
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
using ll = long long;
#define SZ(x) (int)(x.size())
#define FOR(i,x,y) for (int i = (x),_##i = (y);i < _##i;i++)
#define FORD(i,x,y) for (int i = (x),_##i = (y);i > _##i;i--)
inline void GIL();
int main() {
ios::sync_with_stdio(false);cin.tie(nullptr);
int t = 1;
cin >> t;
FOR (id, 1, t + 1) { GIL(); }
return 0;
}
inline void GIL() {
ll w, f;
cin >> w >> f;
int n;
cin >> n;
ll sum =0;
vector<int> v(n);
FOR (i, 0, n) {
cin >> v[i];
sum += v[i]; // 所有怪物的总和为sum
}
ll mx = max(w, f);
ll l = 1, r = (sum + mx - 1) / mx; // 二分边界,只使用一种法术消灭怪物时的最小时间。
auto check = [&] (ll mid) {
ll sum_w = mid * w, sum_f = mid * f;
ll ALL = min(sum_w, sum_f); // 采取最小的法术作为背包容量。
vector<int> dp(ALL + 1, 0); // 容量为ALL的背包
FOR (i, 0, n) {
FORD (j, ALL, v[i] - 1) {
dp[j] = max(dp[j], dp[j - v[i]] + v[i]); // 0/1背包
}
}
return max(sum_f, sum_w) >= sum - dp[ALL]; // 看另一种法术是否能消灭剩下的怪物。
};
while (l < r) { // 二分时间。
ll mid = (l + r) >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
cout << l << "\n";
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?