一些非常有趣(神秘)的题

工作留痕。

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) \ge dis(i, j) \]

那么如果 \(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;
}
posted @ 2026-10-29 20:56  AxDea  阅读(6)  评论(0)    收藏  举报