Codeforces Round 961 (Div. 2) 补题记录(A~D)
上大分,赢!
A
考虑将每一条对角线上可以存放的砝码数量都记录一下,从大到小排序,然后直接暴力贪心选择。
此时可以发现数量一定形如
时间复杂度为
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 500100;
int a[N];
signed main() {
int T;
scanf("%lld", &T);
while (T--) {
int n, k;
scanf("%lld%lld", &n, &k);
vector<int> v;
v.emplace_back(n);
for (int i = n - 1; i; --i) v.emplace_back(i), v.emplace_back(i);
int cnt = 0;
int i = 0;
while (k > 0) {
k -= v[i];
++cnt;
++i;
}
printf("%lld\n", cnt);
}
}
B2
B1 做法同 B2。
考虑枚举每一个值
然后计算出这个最大的开销,令
开一个 map
计算出
还是这张图:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 500100;
int a[N], b[N];
signed main() {
int T;
scanf("%lld", &T);
while (T--) {
int n, m;
scanf("%lld%lld", &n, &m);
for (int i = 1; i <= n; ++i) scanf("%lld", &a[i]);
for (int i = 1; i <= n; ++i) scanf("%lld", &b[i]);
map<int, int> mp;
for (int i = 1; i <= n; ++i) mp[a[i]] += b[i];
sort(a + 1, a + n + 1);
int mx = 0;
for (int i = 1; i <= n; ++i) {
int key = 0;
int val = a[i];
int remain = mp[a[i]];
remain = min(remain, m / val);
int aix = remain;
key = a[i] * remain;
remain = mp[a[i] + 1];
remain = min(remain, (m - key) / (a[i] + 1));
key += (a[i] + 1) * remain;
remain = min(aix, mp[a[i] + 1] - remain);
key += remain;
if (key > m) key = m;
mx = max(mx, key);
}
printf("%lld\n", mx);
}
}
C
首先考虑一下弱化版 CF1883E 的做法。
每一次将一个数乘以 long long
甚至 __uint128
。因此考虑一些优美的性质:
。
也就是说,可以考虑对于每一个
- 给定一个序列
,每一次可以将某一个元素 ,问多少次操作之后序列单调不递减。
这个问题就可以直接贪心的模拟了。
然后考虑本题。本题要求的是对一个数平方。也考虑同样的转化方式:
。 。
也就是说,
时间复杂度为 long double
否则会被卡精度。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 500100;
int a[N];
long double b[N];
signed main() {
int T;
scanf("%lld", &T);
while (T--) {
int n;
scanf("%lld", &n);
for (int i = 1; i <= n; ++i) scanf("%lld", &a[i]);
bool ok = 1;
for (int i = 2; i <= n; ++i) if (a[i] < a[i - 1]) ok = 0;
if (ok) printf("0\n");
else {
int pre = 0;
ok = 1;
for (int i = 1; i <= n; ++i) {
pre = max(pre, a[i]);
if (a[i] == 1) {
if (pre > 1) {
ok = 0;
break;
}
}
}
if (!ok) puts("-1");
else {
for (int i = 1; i <= n; ++i)
b[i] = log2l(log2l(a[i]));
int cnt = 0;
for (int i = 2; i <= n; ++i) {
if (b[i] < b[i - 1]) {
double qwq = b[i - 1] - b[i];
int kif = (int)ceill(qwq);
cnt += kif;
b[i] += kif;
}
}
printf("%lld\n", cnt);
}
}
}
}
D
考虑 dp。
设
那么显然有下列的初始条件:
,若 为子状态数为 ,且唯一一个子状态为字符串结尾字符。 ,若 状态包含其中一个长度为 的子区间中所有的元素。 ,若 状态同时不满足下列的条件。
但是这显然是错的。因此考虑 dp 更新答案。
按照顺序枚举集合
最终就是在所有满足
时间复杂度为
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 500100;
int a[N], box[N], f[N];
signed main() {
int T;
scanf("%lld", &T);
while (T--) {
int n, c, k;
scanf("%lld%lld%lld", &n, &c, &k);
string s; cin >> s;
for (int i = 0; i < c; ++i) box[i] = 0;
for (int i = 0; i < k; ++i) ++box[s[i] - 'A'];
for (int i = 0; i < (1ll << c); ++i) f[i] = 1;
f[(1ll << (s[n - 1]) - 'A')] = 0;
for (int l = 0, r = k - 1; r < n; ++l, ++r) {
int mask = 0;
for (int j = 0; j < c; ++j)
if (box[j]) mask |= (1ll << j);
f[mask] = 0;
if (r < n - 1)
--box[s[l] - 'A'], ++box[s[r + 1] - 'A'];
}
for (int i = 1; i < (1ll << c); ++i)
for (int j = 0; j < c; ++j)
if (i >> j & 1) f[i] &= f[i ^ (1ll << j)];
int mi = c;
for (int i = 1; i < (1ll << c); ++i)
if (f[i]) mi = min(mi, c - (int)__builtin_popcountll(i));
printf("%lld\n", mi);
}
}
本文来自博客园,作者:yhbqwq,转载请注明原文链接:https://www.cnblogs.com/yhbqwq/p/18320028,谢谢QwQ
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期
· 全程使用 AI 从 0 到 1 写了个小工具
· 从文本到图像:SSE 如何助力 AI 内容实时呈现?(Typescript篇)