[题解] Codeforces Round 895 (Div. 3) F~G
Codeforces Round 895 (Div. 3) F~G
F. Selling a Menageri
考虑如何让卖出的价格翻倍,那么自然是从
现在考虑环上的问题。如果出现一个环,那么会出现循环的问题:我们从哪里开始?因为这里形成了一个简单环,那么说明这个环上需要有一个不能被满足翻倍价格,也就是让其中一个点的前驱优先实现,则此时该边在图上不存在,该基环树变成有向无环图,此时可以通过拓扑排序得到序列。
问题是我们要如何确定让哪个点不被翻倍呢?贪心的想,让环中点权值最小的点不被翻倍即可,即断开在这个环中连向这个权值最小的边断开,即可。
最后,我们只需要对处理后的图跑一遍拓扑,即可得到答案序列。
这里处理环使用了强连通分量找环,写得比较麻烦。
void Main() { int n; std::cin >> n; std::vector<int> a(n); for (auto &item : a) { std::cin >> item; item --; } std::vector<int> vw(n); for (auto &item : vw) { std::cin >> item; } std::vector adj(n, std::vector<int>{}); for (int i = 0; i < n; i ++) { adj[i].emplace_back(a[i]); } std::vector<int> dfn(n, -1), low(n, -1), scc_id(n, -1); std::vector<std::vector<int>> scc; int scc_cnt = 0; std::vector<int> stk; std::vector<bool> inst(n); auto tarjan = [&, stamp{0}](auto &self, int from) mutable -> void { dfn[from] = low[from] = stamp ++; stk.emplace_back(from); inst[from] = true; for (auto to : adj[from]) { if (dfn[to] == -1) { self(self, to); low[from] = std::min(low[from], low[to]); } else if (inst[from]) { low[from] = std::min(low[from], dfn[to]); } } if (dfn[from] == low[from]) { int v; scc.emplace_back(std::vector<int>{}); do { v = stk.back(); stk.pop_back(); inst[v] = false; scc_id[v] = scc_cnt; scc.back().emplace_back(v); } while (v != from); scc_cnt ++; } }; for (int i = 0; i < n; i ++) { if (dfn[i] == -1) { tarjan(tarjan, i); } } std::vector<bool> fuk(n); for (auto &list : scc) { std::ranges::sort(list, std::less{}, [&](auto x) { return vw[x]; }); if (list.size() >= 2) { fuk[list.front()] = true; } } std::vector radj(n, std::vector<int>{}); std::vector<int> ind(n); for (int i = 0; i < n; i ++) { if (!fuk[i]) { radj[i].emplace_back(a[i]); ind[a[i]] ++; } } std::vector<int> ans; ans.reserve(n); for (int i = 0; i < n; i ++) { if (ind[i] == 0) { ans.emplace_back(i); } } for (int i = 0; i < std::min<int>(n, ans.size()); i ++) { int from = ans[i]; for (auto to : radj[from]) { if (-- ind[to] == 0) { ans.emplace_back(to); } } } assert((int)ans.size() == n); for (auto item : ans) { std::cout << item + 1 << ' '; } std::cout << '\n'; }
G. Replace With Product
因为
排除掉之后,我们仍然无法确定中间存在的
如果还是不能确定是不是,还是由于相乘大小增长非常大,假设剩下的大于
因为这些零散的数字比较少,我们直接两重循环遍历求解即可。
void Main() { int n; std::cin >> n; std::vector<i64> a(n); for (auto &item : a) { std::cin >> item; } if (std::ranges::count(a, 1) == n) { std::cout << 1 << ' ' << 1 << '\n'; return; } int l = 0, r = n - 1; while (a[l] == 1) { l ++; } while (a[r] == 1) { r --; } i64 tot = 1; for (int i = l; i <= r; i ++) { tot *= a[i]; if (tot > 1e9) { std::cout << l + 1 << ' ' << r + 1 << '\n'; return; } } std::vector<int> pos; for (int i = l; i <= r; i ++) { if (a[i] > 1) pos.emplace_back(i); } tot = reduce(a.begin(), a.end()); auto pre_ret = tot; int L = 0, R = 0; for (int i = 0; i < pos.size(); i ++) { i64 m = 1, s = 0; for (int j = i; j < pos.size(); j ++) { int l = pos[i], r = pos[j]; m *= a[r]; s += a[r] - 1; auto ret = tot - (r - l + 1) - s + m; if (pre_ret < ret) { pre_ret = ret; L = l; R = r; } } } std::cout << L + 1 << ' ' << R + 1 << '\n'; }
本文作者:FlandreScarlet
本文链接:https://www.cnblogs.com/FlandreScarlet/p/17689908.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步