Codeforces Round 889 (Div. 2)
写在前面
我是飞舞。
A
随便做。
B
发现每一个长度为 的区间中至少有 1 个 的倍数,于是仅需检查能整除 的最长的 的前缀即可。
C1/C2
一个显然的想法是先让所有数同正/同负,再做前缀和/后缀和。
如果某种数的数量不多于 7 个,考虑将这种数变另一种。有 ,则可以通过不多于 5 次操作构造出一个极大/极小值,再用这个极大/极小值对进行操作即可统一符号。此时所需次数上限为 7 + 5 + 19 = 31。
否则两种数的数量肯定都不多于 12,考虑将所有数变为绝对值最大的数,则所需次数上限为:12 + 19 = 31。
代码实现时没有显式地区分上面两种情况,而是对每种数都尝试构造绝对值最大的数并统一符号后取了最小值。
复制复制// /* By:Luckyblock */ #include <cmath> #include <cstdio> #include <cctype> #include <vector> #include <cstring> #include <algorithm> #define pr std::pair #define mp std::make_pair const int kInf = 1e5 + 10; //============================================================= int n, a[50]; int maxa = -kInf, mina = kInf, maxx; int posmaxa, posmina; std::vector <pr <int, int> > ansp, ansn; //============================================================= inline int read() { int f = 1, w = 0; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1; for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0'); return f * w; } int Solvep() { ansp.clear(); int pos = posmaxa, temp = maxa; while (temp < abs(mina)) { temp *= 2; ansp.push_back(mp(pos, pos)); } for (int i = 1; i <= n; ++ i) { if (a[i] < 0) ansp.push_back(mp(i, pos)); } for (int i = 2; i <= n; ++ i) ansp.push_back(mp(i, i - 1)); return ansp.size(); } int Solven() { ansn.clear(); int pos = posmina, temp = mina; while (abs(temp) < abs(maxa)) { temp *= 2; ansn.push_back(mp(pos, pos)); } for (int i = 1; i <= n; ++ i) { if (a[i] > 0) ansn.push_back(mp(i, pos)); } for (int i = n - 1; i; -- i) ansn.push_back(mp(i, i + 1)); return ansn.size(); } void Solve() { bool allpos = 1, allneg = 1; maxa = -kInf, mina = kInf, maxx; for (int i = 1; i <= n; ++ i) { if (a[i] > 0) allneg = 0; if (a[i] < 0) allpos = 0; if (a[i] < mina) mina = a[i], posmina = i; if (a[i] > maxa) maxa = a[i], posmaxa = i; } if (allpos) { printf("%d\n", n - 1); for (int i = 2; i <= n; ++ i) printf("%d %d\n", i, i - 1); return ; } if (allneg) { printf("%d\n", n - 1); for (int i = n - 1; i; -- i) printf("%d %d\n", i, i + 1); return ; } maxx = std::max(abs(maxa), abs(mina)); int cntp = Solvep(), cntn = Solven(); if (cntp < cntn) { printf("%d\n", cntp); for (int i = 0, sz = ansp.size(); i < sz; ++ i) { printf("%d %d\n", ansp[i].first, ansp[i].second); } } else { printf("%d\n", cntn); for (int i = 0, sz = ansn.size(); i < sz; ++ i) { printf("%d %d\n", ansn[i].first, ansn[i].second); } } } //============================================================= int main() { // freopen("1.txt", "r", stdin); int T = read(); while (T --) { n = read(); for (int i = 1; i <= n; ++ i) a[i] = read(); Solve(); } return 0; }
D
发现操作次序无关。考虑先进行若干拓展解锁操作再进行取价值操作。
考虑在牌堆后面加 个 0 来处理拓展过头的问题,显然,如果可以恰好拓展解锁到 并在 处停止拓展并取所有的价值,那么所得价值一定为 。于是仅需考虑能否拓展到某个位置。
很容易想到 的背包,设 表示使用前 张牌能否恰好解锁到位置 (即 作为某次拓展解锁的终点),初始化 ,转移时考虑对第 张牌使用后的影响,则有:
特别地需要置零 ,表示位置 上的牌已经消失了(用于拓展了),这之后位置 已经不会产生贡献了。
在每次转移之前检查 是否成立,如果成立则答案与 取最大值。
发现这玩意可以用 bitset 优化,总时间复杂度变为 级别。呃呃然后就能跑 了,太厉害啦!
// /* By:Luckyblock */ #include <cmath> #include <bitset> #include <cstdio> #include <cctype> #include <cstring> #include <algorithm> #define LL long long const int kN = 1e5 + 10; //============================================================= int n, a[kN << 1]; LL ans, sum[kN << 1]; std::bitset <kN << 1> f; //============================================================= inline int read() { int f = 1, w = 0; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1; for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0'); return f * w; } //============================================================= int main() { // freopen("1.txt", "r", stdin); n = read(); for (int i = 1; i <= n; ++ i) { a[i] = read(); sum[i] = sum[i - 1] + a[i]; } ans = a[1]; f.set(1); for (int i = 1; i <= n; ++ i) { if (f.test(i)) ans = std::max(ans, sum[i] - i + 1); f |= f << a[i]; f.reset(i); } for (int i = n + 1; i <= 2 * n; ++ i) { if (f.test(i)) ans = std::max(ans, sum[n] - i + 1); } printf("%lld\n", ans); return 0; }
写在最后
学到了什么:
bitset
太厉害啦
我是飞舞。
作者@Luckyblock,转载请声明出处。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· Apache Tomcat RCE漏洞复现(CVE-2025-24813)