题解 AtCoder Regular Contest 184 / ARC184A~E
A - Appraiser
如果可以询问
为此,我们将
为了卡这剩下的一次询问,我们拿最后一个大小为
- 如果其他
枚硬币划分的最大的集合超过 ,可以发现这是不可能的,因为这时可疑的硬币数量不够。 - 那么只有两种情况:划分了
和 ,剩余两次询问。 :随意询问一枚硬币与不可疑的硬币,这样可以直接找到 枚可疑硬币,剩下两枚直接随意拿一枚和不可疑的硬币询问,找到最后一枚。 :随意询问 集合中的一枚硬币与不可疑的硬币,如果发现是可疑的,那么这 枚硬币都是可疑的硬币;否则另外 枚硬币和没询问的 枚硬币都是可疑的硬币。
询问次数刚好
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stderr, ##__VA_ARGS__)
#else
#define endl "\n"
#define debug(...) void(0)
#endif
using LL = long long;
int n, m, q;
vector<int> ans;
bool query(int x, int y) {
cout << "? " << x << " " << y << endl;
int ret;
cin >> ret;
return ret;
}
void work(int l, int r) {
vector<int> st[2];
st[0].push_back(l);
for (int i = l + 1; i <= r; i++) st[query(l, i)].push_back(i);
if (st[0].size() == st[1].size()) {
int tmp = l == 1 ? r + 1 : 1;
ans = st[!query(tmp, st[0].front())];
} else {
if (st[0].size() > st[1].size()) swap(st[0], st[1]);
for (int x : st[0]) ans.push_back(x);
}
}
int main() {
#ifndef LOCAL
#endif
cin >> n >> m >> q;
for (int i = 0; i < 50 - 1; i++) work(i * 20 + 1, (i + 1) * 20);
if (!ans.empty() && ans.size() < 10) work(49 * 20 + 1, 50 * 20);
else if (ans.empty()) {
int l = 49 * 20 + 1, r = 50 * 20;
vector<int> st[2];
st[0].push_back(l);
for (int i = l + 1; i <= r - 2; i++) st[query(l, i)].push_back(i);
if (st[0].size() < st[1].size()) swap(st[0], st[1]);
if (st[0].size() == 10) {
if (query(st[0][0], 1)) ans = st[0];
else ans = st[1], ans.push_back(r - 1), ans.push_back(r);
} else {
if (query(st[0][0], 1)) ans = st[0];
else ans = st[1];
if (query(r, 1)) ans.push_back(r);
else ans.push_back(r - 1);
}
}
cout << "! ";
for (int x : ans) cout << x << " ";
cout << endl;
return 0;
}
B - 123 Set
考虑将数字写为
但是
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stderr, ##__VA_ARGS__)
#else
#define endl "\n"
#define debug(...) void(0)
#endif
#define popcount __builtin_popcount
using LL = long long;
void work(vector<int>& a) {
for (int j = 0; 1 << j < a.size(); j++) {
for (size_t i = a.size(); i--; ) {
if (i >> j & 1) a[i ^ (1 << j)] = min(a[i ^ (1 << j)], a[i]);
}
}
}
int solve(int n) {
vector<int> a;
for (LL now = n; now; now /= 3) a.push_back(__lg(now));
vector<int> b(a[0] + 1);
for (size_t i = 0; i < a.size(); i++) b[a[i]] = i + 1;
for (int i = a[0]; i >= 1; i--) b[i - 1] = max(b[i - 1], b[i]);
vector<int> f(1 << b[0], 1e9);
f[0] = 0;
for (int i = 0; i <= a[0]; i++) {
debug("b[%d] = %d\n", i, b[i]);
int U = (1 << b[i]) - 1;
for (size_t i = 0; i < f.size(); i++) f[i & U] = min(f[i & U], f[i]);
f.resize(1 << b[i]);
vector<int> nxt(1 << b[i], 1e9);
work(f);
for (int S = 0; S < 1 << b[i]; S++) {
int T = (S | S << 1) & U;
nxt[S] = min(nxt[S], popcount(S) + f[U ^ T]);
}
f = move(nxt);
}
debug("solve(%d) = %d\n", n, *min_element(f.begin(), f.end()));
return *min_element(f.begin(), f.end());
}
int n, ans;
int calc(int r) {
return (r >= 1 ? (r - 1) / 6 + 1 : 0) + (r >= 5 ? (r - 5) / 6 + 1 : 0);
}
int main() {
#ifndef LOCAL
cin.tie(nullptr)->sync_with_stdio(false);
#endif
cin >> n;
//ans += (n - 1) / 6 + 1;
//if (n >= 5) ans += (n - 5) / 6 + 1;
//for (int x = 0; x <= n / 3 - 1; x += 6) ans += solve(n / (x + 1)) - 1;
//for (int x = 0; x <= n / 3 - 5; x += 6) ans += solve(n / (x + 5)) - 1;
for (int l = 1, r; l <= n; l = r + 1) {
r = n / (n / l);
if (calc(l - 1) != calc(r)) ans += solve(n / l) * (calc(r) - calc(l - 1));
}
cout << ans << endl;
return 0;
}
C - Mountain and Valley Folds
你去找一张纸折一下,折
那么做法就很显然了,搞个类似匹配的东西,对于
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stderr, ##__VA_ARGS__)
#else
#define endl "\n"
#define debug(...) void(0)
#endif
using LL = long long;
constexpr int N = 3e5;
int n, ch[N][2], tot, cnt[N], ans;
int conbit(LL x, int b) { return b <= 60 ? x >> b & 1 : 0; }
void dfs(int u, int now) {
ans = max(ans, now += cnt[u]);
for (int r : {0, 1}) if (ch[u][r]) dfs(ch[u][r], now);
}
int main() {
#ifndef LOCAL
cin.tie(nullptr)->sync_with_stdio(false);
#endif
cin >> n;
for (int i = 1; i <= n; i++) {
LL x;
cin >> x;
int p = 0, u = 0;
for (int j = 0; j < 100; j++) {
for (int r : {0, 1}) if (!ch[u][r]) ch[u][r] = ++tot;
int b = conbit(x, j), r = p + b == 1;
for (int rp : {0, 1}) {
int v = ch[u][!r];
if ((conbit(x, j + 1) + (!r + b + p) / 2 + rp) & 1) {
if (!ch[v][rp]) ch[v][rp] = ++tot;
cnt[ch[v][rp]] += 1;
}
}
p = (r + b + p) >> 1;
u = ch[u][r];
}
}
dfs(0, 0);
cout << ans << endl;
return 0;
}
D - Erase Balls 2D
定义
点击查看代码
#include "atcoder/modint"
#include <bits/stdc++.h>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stderr, ##__VA_ARGS__)
#else
#define endl "\n"
#define debug(...) void(0)
#endif
using LL = long long;
using mint = atcoder::modint998244353;
int n, a[310];
mint f[310], c[310][310];
int main() {
#ifndef LOCAL
cin.tie(nullptr)->sync_with_stdio(false);
#endif
cin >> n;
for (int i = 1, x, y; i <= n; i++) cin >> x >> y, a[x] = n - y + 1;
f[0] = 1;
a[n + 1] = n + 1;
for (int i = 1; i <= n; i++) {
for (int l = 0; l < i; l++) if (a[l] < a[i]) {
for (int r = i + 1; r <= n + 1; r++) if (a[i] < a[r]) c[l][r] += 1;
}
}
for (int i = 0; i <= n; i++) {
for (int j = i + 1; j <= n + 1; j++) if (a[i] < a[j]) {
bool flag = false;
for (int k = i + 1; k < j && !flag; k++) if (a[i] < a[k] && a[k] < a[j] && c[i][k] + c[k][j] + 1 == c[i][j]) flag = true;
if (!flag) f[j] += f[i];
}
}
cout << f[n + 1].val() << endl;
return 0;
}
E - Accumulating Many Times
首先不要读错题目了。然后我们稍微想一下怎么求单个
但是单个
接下来的一步是尝试将可以互相转化的
点击查看代码
atcoder::
含量达到了惊人的
#include "atcoder/all"
#include <bits/stdc++.h>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stderr, ##__VA_ARGS__)
#else
#define endl "\n"
#define debug(...) void(0)
#endif
using LL = long long;
using mint = atcoder::modint998244353;
int n, m;
vector<int> perf(const vector<int>& vec, int stp) {
int n = vec.size();
vector<int> tmp(n);
for (int j = 0; j < n; j++) tmp[j] = (stp & (j + stp)) == stp;
auto&& ret = atcoder::convolution<998244353>(vec, tmp);
for (int j = 0; j < n; j++) tmp[j] = ret[j] & 1;
return tmp;
}
auto work() {
vector<int> vec(m);
for (int i = 0; i < m; i++) cin >> vec[i];
auto bg = vec.begin(), ed = vec.end();
while (bg != vec.end() && *bg == 0) ++bg;
int stp = 0, sz = ed - bg;
for (int j = 1; j < sz; j <<= 1) {
vector<int> slic(bg, bg + min(j << 1, sz));
if (!perf(slic, stp)[j]) stp += j, assert(perf(slic, stp)[j]);
}
return make_pair(perf(vec, stp), stp);
}
map<vector<int>, vector<int>> mp;
int main() {
#ifndef LOCAL
cin.tie(nullptr)->sync_with_stdio(false);
#endif
cin >> n >> m;
for (int i = 1; i <= n; i++) {
auto&& e = work();
mp[e.first].push_back(e.second);
}
mint ans = 0;
for (auto&& e : mp) {
int pos0 = 0;
while (pos0 < (int)e.first.size() && e.first[pos0] == 0) ++pos0;
if (pos0 == (int)e.first.size()) continue;
int p = atcoder::internal::bit_ceil(e.first.size() - pos0);
atcoder::fenwick_tree<mint> fw0(p);
mint prev = 0, pre0 = 0;
for (auto&& x : e.second) {
ans += prev - pre0 * x + fw0.sum(0, x) * p;
prev += x, pre0 += 1, fw0.add(x, 1);
}
}
cout << ans.val() << endl;
return 0;
}
update:避免使用 NTT 的方法,参见 https://www.luogu.com/article/1z7le77j
本文来自博客园,作者:caijianhong,转载请注明原文链接:https://www.cnblogs.com/caijianhong/p/18427478/solution-arc184
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
2023-09-23 题解 Gym 104077I【[ICPC2022 Xi'an R] Square Grid】
2023-09-23 题解 CF1257G【Divisor Set】
2023-09-23 题解 ARC165F【Make Adjacent】
2023-09-23 题解 SS230923C【国境线(boundary)】
2023-09-23 题解 SS230922B【快哭了 (kk)】
2023-09-23 题解 SS230922A【糗大了 (qd)】
2023-09-23 题解 SS230922D【发怒 (fn)】