C – 2D Plane 2N Points
可以考虑先排个序,然后贪心的、暴力的处理即可。
@@ -0,0 +1,36 @@
// ARC092A.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 210;
int n;
bool enabled[MAX_N];
struct point
{
int x, y, typ;
bool operator<(const point &rhs) const { return x < rhs.x; }
} pts[MAX_N];
int main()
{
scanf("%d", &n);
for (int i = 1; i <= (n << 1); i++)
scanf("%d%d", &pts[i].x, &pts[i].y), pts[i].typ = i > n;
sort(pts + 1, pts + 1 + (n << 1));
int ans = 0;
for (int i = 1; i <= (n << 1); i++)
if (pts[i].typ == 1)
{
int id = -1;
for (int j = 1; j < i; j++)
if (!enabled[j] && pts[j].typ == 0 && pts[j].y < pts[i].y && (id == -1 || pts[j].y > pts[id].y))
id = j;
if (id != -1)
enabled[id] = true, ans++;
}
printf("%d\n", ans);
return 0;
}
@@ -0,0 +1,36 @@
// ARC092A.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 210;
int n;
bool enabled[MAX_N];
struct point
{
int x, y, typ;
bool operator<(const point &rhs) const { return x < rhs.x; }
} pts[MAX_N];
int main()
{
scanf("%d", &n);
for (int i = 1; i <= (n << 1); i++)
scanf("%d%d", &pts[i].x, &pts[i].y), pts[i].typ = i > n;
sort(pts + 1, pts + 1 + (n << 1));
int ans = 0;
for (int i = 1; i <= (n << 1); i++)
if (pts[i].typ == 1)
{
int id = -1;
for (int j = 1; j < i; j++)
if (!enabled[j] && pts[j].typ == 0 && pts[j].y < pts[i].y && (id == -1 || pts[j].y > pts[id].y))
id = j;
if (id != -1)
enabled[id] = true, ans++;
}
printf("%d\n", ans);
return 0;
}
@@ -0,0 +1,36 @@ // ARC092A.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 210; int n; bool enabled[MAX_N]; struct point { int x, y, typ; bool operator<(const point &rhs) const { return x < rhs.x; } } pts[MAX_N]; int main() { scanf("%d", &n); for (int i = 1; i <= (n << 1); i++) scanf("%d%d", &pts[i].x, &pts[i].y), pts[i].typ = i > n; sort(pts + 1, pts + 1 + (n << 1)); int ans = 0; for (int i = 1; i <= (n << 1); i++) if (pts[i].typ == 1) { int id = -1; for (int j = 1; j < i; j++) if (!enabled[j] && pts[j].typ == 0 && pts[j].y < pts[i].y && (id == -1 || pts[j].y > pts[id].y)) id = j; if (id != -1) enabled[id] = true, ans++; } printf("%d\n", ans); return 0; }
D – Two Sequences
这个题还蛮有意思的,让我想起某个 Div.1 B。
我们可以从低位到高位考虑。设 \(T = p^b, mod = 2T\),那么我们先把所有的 \(a_i, b_i\) 对 \(mod\) 取个模,然后可以发现的是,对于固定的 \(b_i\),如果 \(T \leq a_i + b_i < 2T, 3T \leq a_i + b_i < 4T\),那么这个位的贡献就是 \(1\)。我们可以在取模之后来二分出这个区间,得到答案。
@@ -0,0 +1,38 @@
// ARC092B.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 2e5 + 200;
int n, ai[MAX_N], bi[MAX_N], ta[MAX_N], tb[MAX_N];
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &ai[i]);
for (int i = 1; i <= n; i++)
scanf("%d", &bi[i]);
int ans = 0;
for (int b = 0; b < 29; b++)
{
int T = 1 << b, mod = T << 1;
for (int i = 1; i <= n; i++)
ta[i] = ai[i] % mod, tb[i] = bi[i] % mod;
sort(tb + 1, tb + 1 + n);
int pans = 0;
for (int i = 1; i <= n; i++)
{
int l = lower_bound(tb + 1, tb + 1 + n, T - ta[i]) - tb;
int r = lower_bound(tb + 1, tb + 1 + n, mod - ta[i]) - tb;
pans ^= (r - l) & 1;
l = lower_bound(tb + 1, tb + 1 + n, T * 3 - ta[i]) - tb;
r = lower_bound(tb + 1, tb + 1 + n, (mod << 1) - ta[i]) - tb;
pans ^= (r - l) & 1;
}
ans += (pans << b);
}
printf("%d\n", ans);
return 0;
}
@@ -0,0 +1,38 @@
// ARC092B.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 2e5 + 200;
int n, ai[MAX_N], bi[MAX_N], ta[MAX_N], tb[MAX_N];
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &ai[i]);
for (int i = 1; i <= n; i++)
scanf("%d", &bi[i]);
int ans = 0;
for (int b = 0; b < 29; b++)
{
int T = 1 << b, mod = T << 1;
for (int i = 1; i <= n; i++)
ta[i] = ai[i] % mod, tb[i] = bi[i] % mod;
sort(tb + 1, tb + 1 + n);
int pans = 0;
for (int i = 1; i <= n; i++)
{
int l = lower_bound(tb + 1, tb + 1 + n, T - ta[i]) - tb;
int r = lower_bound(tb + 1, tb + 1 + n, mod - ta[i]) - tb;
pans ^= (r - l) & 1;
l = lower_bound(tb + 1, tb + 1 + n, T * 3 - ta[i]) - tb;
r = lower_bound(tb + 1, tb + 1 + n, (mod << 1) - ta[i]) - tb;
pans ^= (r - l) & 1;
}
ans += (pans << b);
}
printf("%d\n", ans);
return 0;
}
@@ -0,0 +1,38 @@ // ARC092B.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 2e5 + 200; int n, ai[MAX_N], bi[MAX_N], ta[MAX_N], tb[MAX_N]; int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &ai[i]); for (int i = 1; i <= n; i++) scanf("%d", &bi[i]); int ans = 0; for (int b = 0; b < 29; b++) { int T = 1 << b, mod = T << 1; for (int i = 1; i <= n; i++) ta[i] = ai[i] % mod, tb[i] = bi[i] % mod; sort(tb + 1, tb + 1 + n); int pans = 0; for (int i = 1; i <= n; i++) { int l = lower_bound(tb + 1, tb + 1 + n, T - ta[i]) - tb; int r = lower_bound(tb + 1, tb + 1 + n, mod - ta[i]) - tb; pans ^= (r - l) & 1; l = lower_bound(tb + 1, tb + 1 + n, T * 3 - ta[i]) - tb; r = lower_bound(tb + 1, tb + 1 + n, (mod << 1) - ta[i]) - tb; pans ^= (r - l) & 1; } ans += (pans << b); } printf("%d\n", ans); return 0; }
E – Both Sides Merger
首先有一个性质:最后对答案贡献的数的下标奇偶性相同。这是个充要条件,所以我们可以直接分类讨论,得到最后的答案。
@@ -0,0 +1,47 @@
// ARC092C.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1010;
typedef long long ll;
int n, ai[MAX_N];
ll sum[2];
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &ai[i]), sum[i & 1] += max(0, ai[i]);
if (max(sum[0], sum[1]) == 0)
{
int pos = max_element(ai + 1, ai + 1 + n) - ai;
printf("%d\n%d\n", ai[pos], n - 1);
for (int i = n; i > pos; i--)
printf("%d\n", i);
for (int i = pos - 1; i >= 1; i--)
puts("1");
return 0;
}
int parity = sum[1] >= sum[0];
vector<int> pos, ans;
for (int i = 1; i <= n; i++)
if (ai[i] > 0 && i % 2 == parity)
pos.push_back(i);
for (int i = n; i > pos.back(); i--)
ans.push_back(i);
for (int i = 1; i < pos.front(); i++)
ans.push_back(1);
for (int i = 0, siz = pos.size(); i < siz - 1; i++)
{
for (int j = 0; j < ((pos[i + 1] - pos[i] - 1) >> 1); j++)
ans.push_back(3);
ans.push_back(2);
}
printf("%lld\n%lld\n", sum[parity], 1LL * ans.size());
for (int v : ans)
printf("%d\n", v);
return 0;
}
@@ -0,0 +1,47 @@
// ARC092C.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1010;
typedef long long ll;
int n, ai[MAX_N];
ll sum[2];
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &ai[i]), sum[i & 1] += max(0, ai[i]);
if (max(sum[0], sum[1]) == 0)
{
int pos = max_element(ai + 1, ai + 1 + n) - ai;
printf("%d\n%d\n", ai[pos], n - 1);
for (int i = n; i > pos; i--)
printf("%d\n", i);
for (int i = pos - 1; i >= 1; i--)
puts("1");
return 0;
}
int parity = sum[1] >= sum[0];
vector<int> pos, ans;
for (int i = 1; i <= n; i++)
if (ai[i] > 0 && i % 2 == parity)
pos.push_back(i);
for (int i = n; i > pos.back(); i--)
ans.push_back(i);
for (int i = 1; i < pos.front(); i++)
ans.push_back(1);
for (int i = 0, siz = pos.size(); i < siz - 1; i++)
{
for (int j = 0; j < ((pos[i + 1] - pos[i] - 1) >> 1); j++)
ans.push_back(3);
ans.push_back(2);
}
printf("%lld\n%lld\n", sum[parity], 1LL * ans.size());
for (int v : ans)
printf("%d\n", v);
return 0;
}
@@ -0,0 +1,47 @@ // ARC092C.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 1010; typedef long long ll; int n, ai[MAX_N]; ll sum[2]; int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &ai[i]), sum[i & 1] += max(0, ai[i]); if (max(sum[0], sum[1]) == 0) { int pos = max_element(ai + 1, ai + 1 + n) - ai; printf("%d\n%d\n", ai[pos], n - 1); for (int i = n; i > pos; i--) printf("%d\n", i); for (int i = pos - 1; i >= 1; i--) puts("1"); return 0; } int parity = sum[1] >= sum[0]; vector<int> pos, ans; for (int i = 1; i <= n; i++) if (ai[i] > 0 && i % 2 == parity) pos.push_back(i); for (int i = n; i > pos.back(); i--) ans.push_back(i); for (int i = 1; i < pos.front(); i++) ans.push_back(1); for (int i = 0, siz = pos.size(); i < siz - 1; i++) { for (int j = 0; j < ((pos[i + 1] - pos[i] - 1) >> 1); j++) ans.push_back(3); ans.push_back(2); } printf("%lld\n%lld\n", sum[parity], 1LL * ans.size()); for (int v : ans) printf("%d\n", v); return 0; }
F – Two Faced Edges
一种暴力做法是直接 \(\Theta(nm + m^2)\) 去做 Tarjan,但是会 gg。我们仔细思考一条边的方向对于 SCC 的影响。如果这个边反转之后并不能形成一个新的 SCC 或者是破坏原来的 SCC,那么这个就不会变。
我们发现一条边形成 SCC 和破坏 SCC 是独立影响的,所以我们分开考虑。破坏一个 SCC 当且仅当边 \((u, v)\) 反转之后 \(u\) 无法到达 \(v\),这样我们确实破坏了一个 SCC。这个东西我们其实可以通过做不同顺序的 Tarjan 来得到不同的 dfn 和 low,进而判断是否有第二条路可走。
那么对于形成一个 SCC,当且仅当 \(b_i\) 无法到达 \(a_i\)。这个同理。这两个问题的结果进行异或之后就是答案了。
@@ -0,0 +1,63 @@
// ARC092D.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1010, MAX_E = 2e5 + 200;
int n, m, mp[MAX_N][MAX_N], etot, ui[MAX_E], vi[MAX_E], p[MAX_N], q[MAX_N];
bool accessible[MAX_N][MAX_N], vis[MAX_N], enabled[MAX_N][MAX_N];
vector<int> G[MAX_N];
void mark(int u, int root)
{
vis[u] = true, accessible[root][u] = true;
for (int v : G[u])
if (!vis[v])
mark(v, root);
}
void markPos(int u)
{
vis[u] = true;
for (int v : G[u])
if (!vis[v])
p[v] = mp[u][v], markPos(v);
}
void markNeg(int u)
{
vis[u] = true;
int siz = G[u].size() - 1;
for (int i = siz; i >= 0; i--)
{
int v = G[u][i];
if (!vis[v])
q[v] = mp[u][v], markNeg(v);
}
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1, u, v; i <= m; i++)
{
scanf("%d%d", &u, &v);
ui[++etot] = u, vi[etot] = v;
mp[u][v] = etot, G[u].push_back(v);
}
for (int i = 1; i <= n; i++)
mark(i, i), memset(vis, false, sizeof(vis));
for (int i = 1; i <= n; i++)
{
markPos(i), memset(vis, false, sizeof(vis));
markNeg(i), memset(vis, false, sizeof(vis));
for (int v : G[i])
if (p[v] != mp[i][v] || q[v] != mp[i][v])
enabled[i][v] = true;
memset(p, 0, sizeof(p)), memset(q, 0, sizeof(q));
}
for (int i = 1; i <= m; i++)
puts((accessible[vi[i]][ui[i]] ^ enabled[ui[i]][vi[i]]) ? "diff" : "same");
return 0;
}
@@ -0,0 +1,63 @@
// ARC092D.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1010, MAX_E = 2e5 + 200;
int n, m, mp[MAX_N][MAX_N], etot, ui[MAX_E], vi[MAX_E], p[MAX_N], q[MAX_N];
bool accessible[MAX_N][MAX_N], vis[MAX_N], enabled[MAX_N][MAX_N];
vector<int> G[MAX_N];
void mark(int u, int root)
{
vis[u] = true, accessible[root][u] = true;
for (int v : G[u])
if (!vis[v])
mark(v, root);
}
void markPos(int u)
{
vis[u] = true;
for (int v : G[u])
if (!vis[v])
p[v] = mp[u][v], markPos(v);
}
void markNeg(int u)
{
vis[u] = true;
int siz = G[u].size() - 1;
for (int i = siz; i >= 0; i--)
{
int v = G[u][i];
if (!vis[v])
q[v] = mp[u][v], markNeg(v);
}
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1, u, v; i <= m; i++)
{
scanf("%d%d", &u, &v);
ui[++etot] = u, vi[etot] = v;
mp[u][v] = etot, G[u].push_back(v);
}
for (int i = 1; i <= n; i++)
mark(i, i), memset(vis, false, sizeof(vis));
for (int i = 1; i <= n; i++)
{
markPos(i), memset(vis, false, sizeof(vis));
markNeg(i), memset(vis, false, sizeof(vis));
for (int v : G[i])
if (p[v] != mp[i][v] || q[v] != mp[i][v])
enabled[i][v] = true;
memset(p, 0, sizeof(p)), memset(q, 0, sizeof(q));
}
for (int i = 1; i <= m; i++)
puts((accessible[vi[i]][ui[i]] ^ enabled[ui[i]][vi[i]]) ? "diff" : "same");
return 0;
}
@@ -0,0 +1,63 @@ // ARC092D.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 1010, MAX_E = 2e5 + 200; int n, m, mp[MAX_N][MAX_N], etot, ui[MAX_E], vi[MAX_E], p[MAX_N], q[MAX_N]; bool accessible[MAX_N][MAX_N], vis[MAX_N], enabled[MAX_N][MAX_N]; vector<int> G[MAX_N]; void mark(int u, int root) { vis[u] = true, accessible[root][u] = true; for (int v : G[u]) if (!vis[v]) mark(v, root); } void markPos(int u) { vis[u] = true; for (int v : G[u]) if (!vis[v]) p[v] = mp[u][v], markPos(v); } void markNeg(int u) { vis[u] = true; int siz = G[u].size() - 1; for (int i = siz; i >= 0; i--) { int v = G[u][i]; if (!vis[v]) q[v] = mp[u][v], markNeg(v); } } int main() { scanf("%d%d", &n, &m); for (int i = 1, u, v; i <= m; i++) { scanf("%d%d", &u, &v); ui[++etot] = u, vi[etot] = v; mp[u][v] = etot, G[u].push_back(v); } for (int i = 1; i <= n; i++) mark(i, i), memset(vis, false, sizeof(vis)); for (int i = 1; i <= n; i++) { markPos(i), memset(vis, false, sizeof(vis)); markNeg(i), memset(vis, false, sizeof(vis)); for (int v : G[i]) if (p[v] != mp[i][v] || q[v] != mp[i][v]) enabled[i][v] = true; memset(p, 0, sizeof(p)), memset(q, 0, sizeof(q)); } for (int i = 1; i <= m; i++) puts((accessible[vi[i]][ui[i]] ^ enabled[ui[i]][vi[i]]) ? "diff" : "same"); return 0; }