一些非常有趣(神秘)的题
工作留痕。
CERC 2025 I. Identical Fences
这尼玛啥
题目等价于找出字符串中两个不相交的相同的子序列。
一个思路是对于一边的子序列,先存着一段等着另一边的子序列匹配,是一个类似 dp 的想法。
具体实现的话,就是搞一个队列,从左往右扫这个字符串,对于一个新的字符 \(c\),如果队列为空,或者 \(c\) 不等于队头,那么将这个字符扔到队尾,否则将这个字符和队首分别放到两个字符串里面,也就是匹配成功。
然后你发现这个玩意非常难卡,数据随机交上去直接突破 \(99\%\)。
所以这个 \(84\%\) 是干啥的。
#include<bits/stdc++.h>
#define forn(i,s,t) for(int i=(s);i<=(t);++i)
#define form(i,s,t) for(int i=(s);i>=(t);--i)
#define rep(i,s,t) for(int i=(s);i<(t);++i)
using namespace std;
typedef long long ll;
const int Mod = 998244353;
void solve() {
int n;
cin >> n;
string s;
cin >> s;
vector<int> A, B;
deque<pair<int, int>> u, v;
rep (i, 0, n) {
char c = s[i] & 1;
if (u.size()) {
if (u.front().first == c) {
A.push_back(u.front().second);
B.push_back(i);
u.pop_front();
} else {
u.push_back(make_pair(c, i));
}
} else if (v.size()) {
if (v.front().first == c) {
B.push_back(v.front().second);
A.push_back(i);
v.pop_front();
} else {
v.push_back(make_pair(c, i));
}
} else {
u.push_back(make_pair(c, i));
}
}
cout << A.size() << '\n';
for (int v : A) cout << v << ' ';
cout << '\n';
for (int v : B) cout << v << ' ';
cout << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int zeg = 1;
// cin >> zeg;
while (zeg -- ) solve();
return 0;
}
/*
*/
CERC 2025 K. Key Properties
是否有点过于有新意了。
神秘构造,可以发现奇数的时候一定无解,因为 \(2\not\mid 3n\)。
然后搞两个环,这个时候所有点的度数为 \(2\),考虑两个环上的点一一对应连边,但是要保证不存在长度为 \(4\) 的环,所以第一个环上相邻的两个点在另一个换上对应的两个点不能相邻。
怎么办呢,你想到了对于 \(\gcd (k, n) = 1\) 的 \(k\),从一个点出发,设为 \(u\),那么对于任意 \(t = 0, 1, \cdots, n - 1\),\(u + tk\) 在模 \(n\) 意义下两两不同。
所以直接暴力搜索所有 \(k > 1\),找到一个合法的 \(k\) 构造就可以了。
#include<bits/stdc++.h>
#define forn(i,s,t) for(int i=(s);i<=(t);++i)
#define form(i,s,t) for(int i=(s);i>=(t);--i)
#define rep(i,s,t) for(int i=(s);i<(t);++i)
using namespace std;
typedef long long ll;
void solve() {
int n;
cin >> n;
if (n & 1) cout << "NO\n";
else {
cout << n + n / 2 << '\n';
forn (i, 1, n / 2 - 1) {
cout << i << ' ' << i + 1 << '\n';
}
cout << 1 << ' ' << n / 2 << '\n';
forn (i, n / 2 + 1, n - 1) {
cout << i << ' ' << i + 1 << '\n';
}
cout << n / 2 + 1 << ' ' << n << '\n';
int del = -1;
forn (i, 2, n / 2) if (__gcd(i, n / 2) == 1) {
del = i; break ;
}
forn (i, 1, n / 2) {
cout << i << ' ' << n / 2 + (1ll * i * del - 1) % (n / 2) + 1 << '\n';
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int zeg = 1;
// cin >> zeg;
while (zeg -- ) solve();
return 0;
}
The 4th Universal Cup. Stage 3: Polar Grand Prix G. Far Away
神了。
首先可以想到如果选择一个点 \(u\) 做全图 bfs,那么有:
那么如果 \(dis(u, i) + dis(u, j) \le 20000\),就可以确认询问 \((i, j)\) 满足 \(dist(i, j)\le 20000\)。
然后这个题一看就是什么神秘乱搞题,直接随机化选 \(u\),多跑几遍,然后就过了。
考虑正确性,可以发现,对于每一个询问满足 \(dist(i, j)\le 20000\),都有至少 \(20000\) 个点可以得到 \(dist(u, i) + dist(v, j) \le 20000\),因为边权总为 \(1\),这个概率还是很大的,多跑几遍就是错误率就是指数级下降。
#include <bits/stdc++.h>
constexpr int C_ = 20'000;
constexpr int inf = 1'000'000'010;
int main() {
std::cin.tie(0)->sync_with_stdio(0);
auto begin = std::chrono::steady_clock::now().time_since_epoch();
int n, m, q;
std::cin >> n >> m >> q;
std::vector<std::vector<int>> G(n + 1);
for (int rep = 0, u, v; rep < m; ++rep) std::cin >> u >> v, G[u].push_back(v), G[v].push_back(u);
std::vector<std::pair<int, int>> Q(q + 1);
std::vector<int> ans(q + 1, -1);
for (int i = 1; i <= q; ++i) std::cin >> Q[i].first >> Q[i].second;
std::vector<int> bel(n + 1), siz(n + 1);
int cnt = 0;
auto dfs = [&](auto &&self, int u) -> void {
++siz[bel[u]];
for (int v : G[u]) {
if (!bel[v]) bel[v] = bel[u], self(self, v);
}
};
for (int i = 1; i <= n; ++i) {
if (!bel[i]) bel[i] = ++cnt, dfs(dfs, i);
}
for (int i = 1; i <= q; ++i) {
auto [u, v] = Q[i];
if (bel[u] != bel[v]) ans[i] = 1;
else if (siz[bel[u]] <= C_) ans[i] = 0;
}
std::vector<int> dis(n + 1);
std::queue<int> queue;
auto BFS = [&](int root) -> void {
std::ranges::fill(dis, inf);
dis[root] = 0, queue.push(root);
while (!queue.empty()) {
int u = queue.front();
queue.pop();
for (int v : G[u]) {
if (dis[v] == inf) dis[v] = dis[u] + 1, queue.push(v);
}
}
};
std::mt19937 roll(114'514);
std::uniform_int_distribution<int> dist(1, n);
for (int rep = 0; rep < 900; ++rep) {
int root = dist(roll);
BFS(root);
for (int i = 1; i <= q; ++i) {
if (ans[i] != -1) continue;
auto [u, v] = Q[i];
if (dis[u] + dis[v] <= C_) ans[i] = 0;
}
if (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock().now().time_since_epoch() - begin).count() > 2500) break;
}
for (int i = 1; i <= q; ++i) {
if (ans[i] == -1) ans[i] = 1;
}
for (int i = 1; i <= q; ++i) std::cout << (ans[i] ? "YES\n" : "NO\n");
}
The 4th Universal Cup. Stage 3: Polar Grand Prix D. Disjoint Set Splitting
可能是最不抽象的题。
你主要到这个答案一定是先全是 1 后全是 0。
然后他这个强制在线比较搞笑,因为你需要利用这一点。
二分最后一个 1 的位置,然后你发现这个强制在线在这里就是滚木,直接删完后判断连通性即可,复杂度线性对数。
#include <bits/stdc++.h>
#define forn(i,s,t) for(int i=(s);i<=(t);++i)
#define rep(i,s,t) for(int i=(s);i<(t);++i)
#define form(i,s,t) for(int i=(s);i>=(t);--i)
using namespace std;
void solve() {
int n, m, q;
cin >> n >> m >> q;
vector<vector<int>> G(n, vector<int>());
forn (i, 1, m) {
int u, v;
cin >> u >> v;
if (u > v) swap(u, v);
G[u].push_back(v);
}
vector<int> a(q + 1, 0), b(q + 1, 0);
forn (i, 1, q) cin >> a[i] >> b[i];
auto check = [&] (int lim) -> bool {
vector<vector<int>> del(n, vector<int>());
int Ux = 0, Vx = 0;
forn (i, 1, lim) {
int u = (Ux + a[i]) % n, v = (Vx + b[i]) % n;
Ux = Ux * 2 + 1, Vx = Vx * 3 + 1;
Ux %= n, Vx %= n;
if (u > v) swap(u, v);
del[u].push_back(v);
}
vector<int> fa(n, 0);
iota(fa.begin(), fa.end(), 0);
auto fnd = [&] (auto&& fnd, int u) -> int {
return fa[u] == u ? u : fa[u] = fnd(fnd, fa[u]);
} ;
auto mrg = [&] (int u, int v) -> void {
u = fnd(fnd, u), v = fnd(fnd, v);
if (u == v) return ;
fa[u] = v;
} ;
vector<int> ton(n, 0);
rep (u, 0, n) {
for (int v : del[u]) ton[v] = 1;
for (int v : G[u]) if (ton[v] == 0) mrg (u, v);
for (int v : del[u]) ton[v] = 0;
} ;
bool fl = 1;
int tmp = fnd(fnd, 0);
rep (i, 1, n) if (tmp != fnd(fnd, i)) fl = 0;
return fl;
} ;
int l = 0, r = q, res = 0;
while (l <= r) {
int mid = (l+r) >> 1;
if (check(mid)) l = mid + 1, res = mid;
else r = mid - 1;
}
forn (i, 1, q) {
if (i <= res) cout << 1;
else cout << 0;
cout << '\n';
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int zeg;
cin >> zeg;
while (zeg -- ) solve();
return 0;
}

浙公网安备 33010602011771号