Codeforces Round 905(div3)解题报告
A. Morning
打的时候没看懂题面 跳了
题目大意
你有一个光标 初始值为1 对于1234567890 你每次可以花费1时间将光标上的数切换成相邻的数
也可以花费1时间将当前光标上的数推入一个队列里
T次询问 每次求构造出一个长度为4的指定队列的最小花费
Solution
首先4次显示一定要花费4的时间
如果把所有0都替换为10 那么切换到第一个数的花费就是
否则 切换到该数的花费就是
时间复杂度
点击查看代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
inline int read() {
int xr = 0, F = 1;
char cr;
while (cr = getchar(), cr < '0' || cr > '9') if (cr == '-') F = -1;
while (cr >= '0' && cr <= '9')
xr = (xr << 3) + (xr << 1) + (cr ^ 48), cr = getchar();
return xr * F;
}
inline void write(ll x) {
int wtop = 0;
char stk[51];
if (x < 0) putchar('-'), x = -x;
do {
stk[++wtop] = x % 10 + '0';
x /= 10;
} while (x);
for (int i = wtop; i; --i) putchar(stk[i]);
}
namespace steven24 {
const int N = 5;
int T;
int a[N];
char s[N];
void main() {
T = read();
while (T--) {
scanf("%s", s);
for (int i = 1; i <= 4; ++i) a[i] = s[i - 1] - '0';
for (int i = 1; i <= 4; ++i) if (!a[i]) a[i] = 10;
int ans = 0;
ans += abs(a[1] - 1);
for (int i = 2; i <= 4; ++i) ans += abs(a[i] - a[i - 1]);
write(ans + 4), putchar('\n');
}
}
}
int main() {
steven24::main();
return 0;
}
B.Chemistry
题目大意
给定一个长度为
你需要在这个字符串里删除恰好
问是否可以做到
Solution
因为字符串可以重新排列 所以我们关心的只是剩余每个字符的出现次数
首先
如果剩余长度为奇数 那么每个字符出现的数量一定是一个字符为奇数 剩余的都为偶数
否则 所有字符的出现次数都应该为偶数
所以我们直接关心原串中出现次数为奇数的字符有多少个 并且能否用
具体的 假设我们要求删完后有
那么我们比较
时间复杂度
点击查看代码
#include <bits/stdc++.h>
using namespace std;
inline int read() {
int xr = 0, F = 1;
char cr;
while (cr = getchar(), cr < '0' || cr > '9') if (cr == '-') F = -1;
while (cr >= '0' && cr <= '9')
xr = (xr << 3) + (xr << 1) + (cr ^ 48), cr = getchar();
return xr * F;
}
namespace steven24 {
int c[31];
int T, n, k;
void main() {
T = read();
while (T--) {
memset(c, 0, sizeof c);
n = read(), k = read();
for (int i = 1; i <= n; ++i) {
char cc;
scanf(" %c", &cc);
++c[cc - 'a'];
}
int cnt = 0;
for (int i = 0; i <= 25; ++i) if (c[i] & 1) ++cnt;
if ((n - k) & 1) {
if (cnt - 1 <= k) puts("YES\n");
else puts("NO\n");
} else {
if (cnt <= k) puts("YES\n");
else puts("NO\n");
}
}
}
}
int main() {
steven24::main();
return 0;
}
C.Raspberries
product 竟然还有乘积的意思
题目大意
给定一个长度为
再给定一个
每次操作可以选择序列中的一个数并把它+1
问使这个序列中所有数的乘积为
Solution
考虑构造 显然要让这个序列中的每个数都拿出来一个因数 然后乘起来恰好为
发现
这也就意味着 在这种情况下 如果序列中存在一个数为
否则就找一个能达到
我们单独考虑
- 如果存在一个为4的倍数 答案就为0
- 否则 如果存在两个为2的倍数 答案也为0
- 否则 如果存在一个为2的倍数 答案就为达到2的倍数需要操作最少的数
- 否则 如果一个为2的倍数的数都没有 答案就为使两个数变为2的倍数/使一个数变为4的倍数取
时间复杂度
点击查看代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
inline int read() {
int xr = 0, F = 1;
char cr;
while (cr = getchar(), cr < '0' || cr > '9') if (cr == '-') F = -1;
while (cr >= '0' && cr <= '9')
xr = (xr << 3) + (xr << 1) + (cr ^ 48), cr = getchar();
return xr * F;
}
void write(ll x) {
char ws[51];
int wt = 0;
if (x < 0) putchar('-'), x = -x;
do {
ws[++wt] = x % 10 + '0';
x /= 10;
} while (x);
for (int i = wt; i; --i) putchar(ws[i]);
}
namespace steven24 {
const int N = 2e5 + 0721;
int step[N], a[N];
int T, n, k;
void main() {
T = read();
while (T--) {
n = read(), k = read();
if (k != 4) {
for (int i = 1; i <= n; ++i) {
int x = read();
step[i] = (k - x % k) % k;
}
int ans = *min_element(step + 1, step + 1 + n);
write(ans), putchar('\n');
} else {
int cnt = 0;
for (int i = 1; i <= n; ++i) {
a[i] = read();
while (!(a[i] & 1)) ++cnt, a[i] >>= 1;
}
if (cnt >= 2) puts("0\n");
else if (cnt == 1) puts("1\n");
else {
bool flag = 1;
for (int i = 1; i <= n; ++i) {
if ((a[i] + 1) % 4 == 0) {
puts("1\n");
flag = 0;
break;
}
}
if (flag) puts("2\n");
}
}
}
}
}
int main() {
steven24::main();
return 0;
}
D.In Love
做的比B和C快多了
题目大意
维护一个可重集合 有
- 加入一个区间
- 删除一个区间
保证至少存在一个该区间
每次操作后 你需要回答是否存在两个区间 使它们不相交
Solution
考虑维护一棵线段树
对于每次加入操作 执行区间+1
对于每次删除操作 执行区间-1
再记录一下当前一共有多少个区间
查询全局最大值是否为区间总数即可
记得先全存下来然后离散化
时间复杂度
点击查看代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
inline int read() {
int xr = 0, F = 1;
char cr;
while (cr = getchar(), cr < '0' || cr > '9') if (cr == '-') F = -1;
while (cr >= '0' && cr <= '9')
xr = (xr << 3) + (xr << 1) + (cr ^ 48), cr = getchar();
return xr * F;
}
void write(ll x) {
char ws[51];
int wt = 0;
if (x < 0) putchar('-'), x = -x;
do {
ws[++wt] = x % 10 + '0';
x /= 10;
} while (x);
for (int i = wt; i; --i) putchar(ws[i]);
}
namespace steven24 {
const int N = 2e5 + 0721;
int b[N];
int q, n, sum;
struct node {
int l, r;
char opt;
} a[N];
void discretization() {
int cnt = 0;
for (int i = 1; i <= q; ++i) {
b[++cnt] = a[i].l;
b[++cnt] = a[i].r;
}
sort(b + 1, b + 1 + cnt);
n = unique(b + 1, b + 1 + cnt) - b - 1;
for (int i = 1; i <= q; ++i) {
a[i].l = lower_bound(b + 1, b + 1 + n, a[i].l) - b;
a[i].r = lower_bound(b + 1, b + 1 + n, a[i].r) - b;
}
}
struct segment_tree {
#define ls (k << 1)
#define rs (k << 1 | 1)
#define mid ((l + r) >> 1)
int tr[N << 2], lazy[N << 2];
inline void add(int k, int val) {
tr[k] += val;
lazy[k] += val;
}
void pushdown(int k) {
add(ls, lazy[k]);
add(rs, lazy[k]);
lazy[k] = 0;
}
inline void pushup(int k) {
tr[k] = max(tr[ls], tr[rs]);
}
void modify(int k, int l, int r, int u, int v, int val) {
if (u <= l && v >= r) {
add(k, val);
return;
}
if (lazy[k]) pushdown(k);
if (u <= mid) modify(ls, l, mid, u, v, val);
if (v > mid) modify(rs, mid + 1, r, u, v, val);
pushup(k);
}
} seg;
void main() {
q = read();
for (int i = 1; i <= q; ++i) scanf(" %c", &a[i].opt), a[i].l = read(), a[i].r = read();
discretization();
for (int i = 1; i <= q; ++i) {
if (a[i].opt == '+') seg.modify(1, 1, n, a[i].l, a[i].r, 1), ++sum;
else seg.modify(1, 1, n, a[i].l, a[i].r, -1), --sum;
if (seg.tr[1] == sum) puts("NO\n");
else puts("YES\n");
}
}
}
int main() {
steven24::main();
return 0;
}
E.Look Back
怎么赛时会被这题卡
题目大意
给定一个长度为
问将原序列变为一个单调不降序列的最小操作次数
Solution
首先有一个比较显然的贪心:从第2个数开始从前往后考虑每一位 每次把一个数变为
证明:
如果此时再将它扩大一倍 那么后一个数可能需要额外扩大一倍 可能不需要 但这样一定不优
这样看起来复杂度是
我们考虑优化这个过程 仅记录上一位扩大了多少次 那么对于当前位我们只需要计算偏移值即可
具体地 设上一位操作的次数为
如果
如果
注意至少要扩大0次 否则会干扰后续计算 所以算完
答案即为
时间复杂度就是一个真正的
点击查看代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
inline ll read() {
ll xr = 0, F = 1;
char cr;
while (cr = getchar(), cr < '0' || cr > '9') if (cr == '-') F = -1;
while (cr >= '0' && cr <= '9')
xr = (xr << 3) + (xr << 1) + (cr ^ 48), cr = getchar();
return xr * F;
}
void write(ll x) {
char ws[51];
int wt = 0;
if (x < 0) putchar('-'), x = -x;
do {
ws[++wt] = x % 10 + '0';
x /= 10;
} while (x);
for (int i = wt; i; --i) putchar(ws[i]);
}
namespace steven24 {
const int N = 1e5 + 0721;
ll a[N], g[N];
int n, T;
ll ans;
void main() {
T = read();
while (T--) {
n = read();
for (int i = 2; i <= n; ++i) g[i] = 0;
for (int i = 1; i <= n; ++i) a[i] = read();
ans = 0;
for (int i = 2; i <= n; ++i) {
ll tmp = a[i];
while (tmp < a[i - 1]) {
tmp <<= 1;
++g[i];
// cout << i << " " << tmp << " " << g[i] <<"\n";
}
tmp = a[i - 1];
while ((tmp << 1) <= a[i]) {
tmp <<= 1;
--g[i];
}
g[i] += g[i - 1];
g[i] = max(0ll, g[i]);
ans += g[i];
// cout << i << " " << g[i] << "\n";
}
write(ans), putchar('\n');
}
}
}
int main() {
steven24::main();
return 0;
}
F.You are so beautiful
卡div2 C.jpg
题目大意
给定一个长度为
询问有多少子区间
Solution
注意到每个对于每个合法的
所以我们直接开一个数组 记录这个位置是否为该值出现的最左的位置
然后我们枚举右端点 对于每个合法的右端点 合法的左端点数量就是一段前缀和
该过程可以用 set 配合 BIT 来实现
时间复杂度
点击查看代码
#include <bits/stdc++.h>
#pragma GCC optimize(2)
#define ll long long
using namespace std;
inline ll read() {
ll xr = 0, F = 1;
char cr;
while (cr = getchar(), cr < '0' || cr > '9') if (cr == '-') F = -1;
while (cr >= '0' && cr <= '9')
xr = (xr << 3) + (xr << 1) + (cr ^ 48), cr = getchar();
return xr * F;
}
void write(ll x) {
char ws[51];
int wt = 0;
if (x < 0) putchar('-'), x = -x;
do {
ws[++wt] = x % 10 + '0';
x /= 10;
} while (x);
for (int i = wt; i; --i) putchar(ws[i]);
}
namespace steven24 {
const int N = 1e5 + 0721;
set<int> s1, s2;
int a[N];
int T, n;
ll ans;
struct BIT {
int tr[N];
inline int lowbit(int x) {
return x & (-x);
}
void update(int x, int val) {
while (x <= n) {
tr[x] += val;
x += lowbit(x);
}
}
int query(int x) {
int ret = 0;
while (x) {
ret += tr[x];
x -= lowbit(x);
}
return ret;
}
} bit;
void init() {
for (int i = 1; i <= n; ++i) bit.tr[i] = 0;
s1.clear();
s2.clear();
ans = 0;
}
void main() {
T = read();
while (T--) {
n = read();
init();
for (int i = 1; i <= n; ++i) a[i] = read();
for (int i = 1; i <= n; ++i) {
if (s1.find(a[i]) == s1.end()) {
s1.insert(a[i]);
bit.update(i, 1);
}
}
for (int i = n; i >= 1; --i) {
if (s2.find(a[i]) == s2.end()) {
s2.insert(a[i]);
ans += bit.query(i);
}
}
write(ans), putchar('\n');
}
}
}
int main() {
steven24::main();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)