Codeforces Round 961 (Div. 2)
写在前面
比赛地址:https://codeforces.com/contest/1995。
上了一百多分,爽!要是把 D 冲出来就直接紫了呃呃然而失败!争取下把上紫!
A
签到。
复制复制// /* By:Luckyblock */ #include <bits/stdc++.h> #define LL long long //============================================================= //============================================================= //============================================================= int main() { // freopen("1.txt", "r", stdin); std::ios::sync_with_stdio(0), std::cin.tie(0); int T; std::cin >> T; while (T --) { int n, k; std::cin >> n >> k; if (k == 0) std::cout << 0 << "\n"; else if (k && k <= n) std::cout << 1 << "\n"; else { int ans = 1; k -= n; for (int i = n - 1; i; -- i) { if (k > 0) ++ ans, k -= i; if (k > 0) ++ ans, k -= i; } std::cout << ans << "\n"; } } return 0; }
B1 & B2
枚举。
不太懂分 B1B2 什么意义、、、过了 B1 两分钟就把 B2 过了呃呃也可能是我 B1 没看题不知道暴力怎么写哈哈
已知每种权值的出现次数,于是仅需考虑对于两个分别出现了 的两个权值 使用代价 可以获得的最大价值。
发现将选择的一个 替换为 会且仅会使价值 +1,则一个显然的想法是先用 凑,剩余部分用 凑,然后检查此时是否:
- 选择了至少一个 。
- 选择 的数量小于 。
- 代价之和小于 。
然后考虑将尽可能多的 替换为 即可,具体讨论过程详见代码。
以下为 B2 代码。
// /* By:Luckyblock */ #include <bits/stdc++.h> #define LL long long const int kN = 2e5 + 10; std::map<int, int> cnt; //============================================================= int n, a[kN]; LL m; //============================================================= //============================================================= int main() { //freopen("1.txt", "r", stdin); std::ios::sync_with_stdio(0), std::cin.tie(0); int T; std::cin >> T; while (T --) { std::cin >> n >> m; cnt.clear(); for (int i = 1; i <= n; ++ i) std::cin >> a[i]; for (int i = 1; i <= n; ++ i) { int c; std::cin >> c; cnt[a[i]] = c; } LL ans = 0; for (int i = 1; i <= n; ++ i) { int c1 = cnt[a[i]], c2 = cnt[a[i] + 1]; LL temp = 1ll * c1 * a[i] + c2 * (a[i] + 1); if (temp <= m) ans = std::max(ans, temp); LL k1 = std::min(1ll * c1, m / (a[i])); temp = k1 * a[i]; LL k2 = std::min(1ll * c2, (m - temp) / (a[i] + 1)); temp += k2 * (a[i] + 1); if (k1 && k2 < c2 && temp < m) { LL delta = std::min(std::min(k1, c2 - k2), (m - temp)); k1 -= delta, k2 += delta, temp += delta; } ans = std::max(ans, temp); } std::cout << ans << "\n"; } return 0; }
C
维护技巧。
看到这题笑死我了太典了实在是
发现可以直接从前往后操作,每次将当前位置的数调整为最小的不小于前一个数的数即可。然而大力平方之后会很大,没法直接比较大小那么没法直接做。
发现 平方 次后为 ,于是仅需考虑如何找到最小的 ,使得:
这个幂次的形式太典了,取个 :
发现有 的幂还是很大,不太好直接比较,那么再取个 :
这下就好做了。每次二分或者直接大力算出来最小的 即可,若求不出来则无解。赛时懒得多想了写了二分,爽!
// /* By:Luckyblock */ #include <bits/stdc++.h> #define LL long long const int kN = 2e5 + 10; const double eps = 1e-9; //============================================================= int n, a[kN]; LL ans, f[kN]; //============================================================= bool notsmaller(LL a_, LL f1_, LL b_, LL f2_) { double lga = log10(1.0 * a_), lgb = log10(1.0 * b_); double lglga = log10(lga), lglgb = log10(lgb); double lg2 = log10(2.0); return (f1_ * lg2 + lglga + eps >= f2_ * lg2 + lglgb); } //============================================================= int main() { // freopen("1.txt", "r", stdin); std::ios::sync_with_stdio(0), std::cin.tie(0); int T; std::cin >> T; while (T --) { std::cin >> n; for (int i = 1; i <= n; ++ i) std::cin >> a[i]; for (int i = 1; i <= n; ++ i) f[i] = 0; ans = 0; for (int i = 2; i <= n; ++ i) { if (notsmaller(a[i], 0, a[i - 1], f[i - 1])) continue; for (LL l = 1, r = 1e10; l <= r; ) { LL mid = (l + r) >> 1ll; if (notsmaller(a[i], mid, a[i - 1], f[i - 1])) { f[i] = mid; r = mid - 1; } else { l = mid + 1; } } if (!f[i]) { ans = -1; break; } ans += f[i]; } std::cout << ans << "\n"; } return 0; }
D
状压 DP。
江队说是套路妈的,场上光想着怎么 check 一个状态是否合法了还能这么搞太牛逼了。
这个数据范围疯狂暗示需要状压,于是考虑状压 DP 求有哪些选择结尾的状态是合法的。
发现题目给定限制,等价于对于所有长度为 的子区间,要求这些子区间中至少有一个字符为结尾字符;且最后一个字符一定为结尾字符。则对于每一个子区间中所有字符,在任一合法的选择结尾的方案中不能同时不出现。于是一个显然的想法是考虑在结尾字符中,不存在哪些字符会使得方案非法。记 表示不存在的结尾字符的状态 时是否合法,初始化:
- 对于每一长为 的子区间,求其中出现的字符状态集合 ,则 。
- 仅包含最后一个字符 的状态 ,有 。
- 除此之外所有其他集合 均有 。
然后按照不存在字符数量枚举集合 ,考虑当前集合是否包含一个非法的子集即可,即有转移:
最后对所有 的状态统计其中 0 的个数取最小值即为答案。
总时间复杂度 级别。
// /* By:Luckyblock */ #include <bits/stdc++.h> #define LL long long const int kN = 1e6 + 10; const int kInf = 1e9 + 2077; const int kC = 20; //============================================================= int n, c, k, all, ans; int cnt[kC]; bool can_delete[kN]; std::string s; //============================================================= void init() { all = (1 << c) - 1, ans = c; for (int i = 0; i <= all; ++ i) can_delete[i] = 1; for (int i = 0; i < c; ++ i) cnt[i] = 0; for (int i = 0; i < k; ++ i) ++ cnt[s[i] - 'A']; for (int l = 0, r = k - 1; r < n; ++ l, ++ r) { int j = 0; for (int i = 0; i < c; ++ i) if (cnt[i]) j |= (1 << i); can_delete[j] = 0; if (r + 1 < n) -- cnt[s[l] - 'A'], ++ cnt[s[r + 1] - 'A']; } can_delete[1 << (s[n - 1] - 'A')] = 0; } void solve() { for (int i = 1; i < all; ++ i) { int cnt0 = 0; for (int j = 0; j < c; ++ j) { if (i >> j & 1) can_delete[i] &= can_delete[i ^ (1 << j)]; else ++ cnt0; } if (can_delete[i]) ans = std::min(ans, cnt0); } } //============================================================= int main() { // freopen("1.txt", "r", stdin); std::ios::sync_with_stdio(0), std::cin.tie(0); int T; std::cin >> T; while (T --) { std::cin >> n >> c >> k; std::cin >> s; init(); solve(); std::cout << ans << "\n"; } return 0; }
写在最后
学到了什么:
- D:预处理状态后自底向下递推。
哎呦我草这个夏和小的音声啊听着一秒不昏过去的都是神人了:【【中文字幕/碧蓝档案】月雪宫子(泳装)ASMR 「在你我二人的小岛上共道早安」】 https://www.bilibili.com/video/BV1zS411w7X6
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧