2024 ICPC ECfinal AEGI

A. Hitoshizuku

贪心。

对右端点排序后,对于没有被匹配的点,每次把小于等于该右端点的维护一下,然后该端点去匹配维护的集合里两个右端点最小的即可。

不会证明,题解说是调整法可得是最优的

点击查看代码
#include<bits/stdc++.h>
using namespace  std;
#define endl '\n'
#define int long long
const int N=3e5+3;
#define int long long
bool cmp(array<int,3>x,array<int,3>y) {
    if (x[1] != y[1])return x[1] < y[1];
    return x[0] > y[0];
}
void solve() {
    int n;
    cin >> n;
    n *= 3;
    vector<array<int, 3>> a;
    multiset<array<int, 3>> st;
    vector<int> vis(n + 1);
    set<array<int, 3>> mp;
    for (int i = 0; i < n; ++i) {
        int x, y;
        cin >> x >> y;
        a.push_back({x, y, i + 1});

        mp.insert({x, y, i + 1});
    }
    std::sort(a.begin(), a.end(), cmp);
    vector<array<int, 3>> ans;

    for (auto [x, y, idx]: a) {

        if (vis[idx])continue;
        vis[idx] = 1;
        if (st.find({y, x, idx}) != st.end()) {
            st.erase(st.find({y, x, idx}));
        }

        while (mp.size() and (*mp.begin())[0] <= y) {
            auto [xx, yy, i] = *mp.begin();
            if (vis[i]) {
                mp.erase(mp.begin());
                continue;
            }
            mp.erase(mp.begin());
            st.insert({yy, xx, i});
        }

        if (st.size() < 2) {
            cout << "No\n";
            return;
        }
        auto [x1, y1, idx1] = *st.begin();
        swap(x1, y1);
        st.erase(st.begin());
        auto [x2, y2, idx2] = *st.begin();
        swap(x2, y2);
        st.erase(st.begin());

        vis[idx] = vis[idx1] = vis[idx2] = 1;
        ans.push_back({idx, idx1, idx2});
    }
    cout << "Yes\n";
    for (auto x: ans) {
        cout << x[0] << ' ' << x[1] << ' ' << x[2] << endl;
    }

}

signed main(){
    ios::sync_with_stdio(false),cin.tie(0);
    int t=1;
    cin>>t;
    while (t--){
        solve();
    }
}

E. Corrupted Scoreboard Log

大模拟,暴搜。

预处理出 \(0\sim 299\)\(1\sim 100\) 的组合字符串,后续处理出每个 \(\text{try}\) 前面的数字就能得到是哪些组合了,注意 \(\text{22tries}\) 这种还可以拆成 \(\text{2 2 tries}\),需要对过没过这道题分开处理。

数据有 \(00\) ,如果你的代码没处理,记得特判。

第一个数字串包含题数罚时和第一个 \(\text{try}\) 的信息,可以枚举信息然后得到题数和罚时,题数最多两位,再分开讨论一下就行。

剩下的是一些细节问题,比如我的一开始是 \(\text{dfs}\) 预处理后面的组合,超时了之后把 \(\text {dfs}\) 挪到枚举里的时候变量名复用了,导致里面 \(\text{dfs}\) 搜索的时候把外面的变量改了 ...

点击查看代码
#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

map<string, vector<array<int, 2>>> mp;

int M;

void solve() {

    string s;
    cin >> s;

    if (s == "00") {
        cout << 0 << " " << 0 << "\n";
        return;
    }

    vector<string> pro;
    int lst = 0;
    for (int i = 0; i < s.size(); i += 1) {
        if (s[i] == 'y' || s[i] == 's') {
            pro.push_back(s.substr(lst, i - lst + 1));
            lst = i + 1;
        }
    }

    int m = pro[0].size(), f = 0;
    m -= 3;
    if (pro[0].back() == 's') {
        m -= 2;
        f = 1;
    }

    int edl = pro.size(), ok = 0;
    auto check = [&](int T, int Fa, string& d)->bool{
        string ans = "";
        vector<array<int, 3>> res;
        auto dfs = [&](auto & self, int idx, int t, int fa)->void{
            if (ok || t < 0 || fa < 0) {
                return;
            }
            if (idx >= pro.size()) {
                if (t == 0 && fa == 0) {
                    cout << ans;
                    int now = 0;
                    for (auto &[x1, y1, st] : res) {
                        if (st) {
                            cout << x1 << " ";
                        }
                        cout << y1 << " " << (y1 > 1 ? "tries" : "try");
                        now += 1;
                        cout << " \n"[now == edl];
                    }
                    ok = 1;
                }
                return;
            }
            string nd = "";
            int len = pro[idx].size(), nf = 0;
            len -= 3;
            if (pro[idx].back() == 's') {
                len -= 2;
                nf = 1;
            }
            nd = pro[idx].substr(0, len);
            for (auto &[x, y] : mp[nd]) {
                if (((nf && y > 1) || (!nf && y == 1))) {
                    res.push_back({x, y, 1});
                    if (to_string(x) + to_string(y) == nd) {
                        self(self, idx + 1, t - 1, fa - x - (y - 1) * 20);
                    }
                    else {
                        res.back()[2] = 0;
                        self(self, idx + 1, t, fa);
                    }
                    res.pop_back();
                }
            }
        };

        for (auto [x, y] : mp[d]) {
            if (((f && y > 1) || (!f && y == 1))) {
                array<int, 2> tar{T - 1, Fa - x - (y - 1) * 20};
                ans = to_string(T) + " " + to_string(Fa) + " ";

                res.push_back({x, y , 1});
                if (to_string(x) + to_string(y) == d) {
                    dfs(dfs, 1, tar[0], tar[1]);
                }
                else {
                    res.back()[2] = 0;
                    tar = {T, Fa};
                    dfs(dfs, 1, tar[0], tar[1]);
                }
                res.pop_back();

                if (ok) {
                    return true;
                }
            }
        }
        return false;
    };

    m -= 1;
    for (int l = 1; l <= 6 && m >= 2; l += 1, m -= 1) {
        string d = pro[0].substr(m, l);
        string num = pro[0].substr(1, m - 1);
        if (num.size() > 7 || !mp.count(d)) {
            continue;
        }
        int T = pro[0][0] - '0';
        int Fa = stoi(num);

        if (check(T, Fa, d)) {
            return ;
        }

        if (pro[0][0] == '1' && pro[0][1] <= '3' && Fa > 10) {
            T = T * 10 + (pro[0][1] - '0');
            Fa = stoi(num.substr(1));
            if (check(T, Fa, d)) {
                return ;
            }
        }
    }

}
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    for (int i = 1; i <= 299; i += 1) {
        string si = to_string(i);
        for (int j = 1; j <= 100; j += 1) {
            string sj = to_string(j);
            mp[si + sj].push_back({i, j});
        }
    }

    for (int i = 1; i <= 100; i += 1) {
        string si = to_string(i);
        mp[si].push_back({0, i});
        si = "0" + si;
        mp[si].push_back({0, i});
    }

    int t;
    cin >> t >> M;
    while (t--) {
        solve();
    }

    return 0;
}

G. Collatz Conjecture

数论。

队友写得,不过看起来他是用 \(\text{pollard}\) 写得,放个官方题解[1]吧。

我们把连续的 $ +B $ 一直加到能 $ /A $ 看成一组操作。这个操作在模 $ B $ 意义下可以看做 $ \times A^{-1} \pmod{B} $。

因为 $ A, B $ 互质,根据欧拉定理有 $ A^{\varphi(B)} \equiv 1 \pmod{B} $,所以在模 $ B $ 意义下一定会进入循环。

考虑数字 $ n $ 本身,一组操作之后会变成不超过 \((n+B(A-1))/A\);如果有 $ n > B $,那么变换之后的数字一定小于 $ n $。如果 $ n \leq B $,那么变换之后的数字不超过 $ B $。

所以按一组操作考虑,最后进入循环的一定是 $ 1 \sim B $ 之间的数字。

看 $ n $ 本身是否会进入循环,只需要考虑 $ 1 \sim B $ 之间与 $ n $ 同余的 $ n' $。这个 $ n' $ 进循环时,如果在成为 $ A $ 的信数前通过 \(+B\) 能到达 \(n\)\(n\) 就在循环里,否则 $ n $ 不可达。

也即,用 $ \text{exgcd} $ 求出最小的非负整数 $ t $ 满足 $ A|n'+tB $,然后看是否有 $ n \leq n'+tB $ 即可。

时间复杂度为 $ O(T\log \min(A,B)) $。

点击查看代码
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#include <bits/stdc++.h>
using namespace  std;
#define endl '\n'
#define int long long
#define LL __int128
const int N = 3e5 + 3;

int qpow(int x, int n, int mod) {
	x %= mod;
	int ans = 1;
	while (n) {
		if (n & 1) {
			ans *= x;
			ans %= mod;
		}
		x *= x;
		x %= mod;
		n >>= 1;
	}
	return ans;
}
#include<bits/stdc++.h>
#define ll long long
#define int long long
const int mod= 998244353;
#define PII pair<ll,int>
#define PIII pair<int,PII>
#define INF 0x3f3f3f3f
#define double long double
using ull = std::uint64_t;
#define endl '\n'
#pragma GCC optimize(2)
using namespace std;
namespace Factor {
	/*Montgomery Multiplt Template*/
	ull modmul(ull a, ull b, ull M) {
		ll ret = a * b - M * ull(1.L / M * a * b);
		return ret + M * (ret < 0) - M * (ret >= (ll) M);
	}
	
	ull modpow(ull b, ull e, ull mod) {
		ull ans = 1;
		for (; e; b = modmul(b, b, mod), e /= 2)
			if (e & 1) ans = modmul(ans, b, mod);
		return ans;
	}
	
	bool isPrime(ull n) {
		if (n < 2 || n % 6 % 4 != 1) return (n | 1) == 3;
		std::vector<ull> A = {2, 325, 9375, 28178, 450775, 9780504, 1795265022};
		ull s = __builtin_ctzll(n - 1), d = n >> s;
		for (ull a: A) {  // ^ count trailing zeroes
			ull p = modpow(a % n, d, n), i = s;
			while (p != 1 && p != n - 1 && a % n && i--) p = modmul(p, p, n);
			if (p != n - 1 && i != s) return 0;
		}
		return 1;
	}
	
	ull pollard(ull n) {
		auto f = [n](ull x, ull k) { return modmul(x, x, n) + 1; };
		ull x = 0, y = 0, t = 30, prd = 2, i = 1, q;
		while (t++ % 40 || std::gcd(prd, n) == 1) {
			if (x == y) x = ++i, y = f(x, i);
			if ((q = modmul(prd, std::max(x, y) - std::min(x, y), n))) prd = q;
			x = f(x, i), y = f(f(y, i), i);
		}
		return std::gcd(prd, n);
	}
	
	std::vector<ull> factor(ull n) {
		if (n == 1) return {};
		if (isPrime(n)) return {n};
		ull x = pollard(n);
		auto l = factor(x), r = factor(n / x);
		l.insert(l.end(), r.begin(), r.end());
		return l;
	}
}
int siz;
vector<ull>fac;
int num[1003];
int res=0;
set<int>st;

void solve() {
	int n, A, B;
	cin >> A >> B >> n;
	fac = Factor::factor(A);
	int w = A;
	sort(fac.begin(), fac.end());
	fac.erase(unique(fac.begin(), fac.end()), fac.end());
	siz = fac.size();
	int sp=1;
	for (int i = 0; i < siz; ++i) {
		num[i] = 0;
		while (w % fac[i] == 0) {
			num[i]++;
			sp*=fac[i];
			w /= fac[i];
		}
		sp/=fac[i];
		sp*=(fac[i]-1);
	}
	LL inv = qpow(B, (sp - 1), A);
	LL l = n - B * min((n % A - B % A + A) % A * inv % A, (LL)n / B);
	LL pt = (A - B % A) % A * inv % A;
	LL s;
	l *= A;
	s = min(pt, l / B);
	l -= s * B;
	if (l % B == n % B && n >= l) {
		cout << "Yes\n";
		return;
	}
	if (l < B) {
		cout << "Yes\n";
		return;
	}
	cout << "No\n";
}

signed main() {
	ios::sync_with_stdio(false),cin.tie(0);
	int t = 1;
	cin >> t;
	while (t--) {
		solve();
	}
}

I. Color-Balanced Tree

二分图染色。

考虑先对整个树进行二分图染色,这样就可以符合同色距离不超过 \(3\) 了,但这样会有颜色数量可能会不对等,此时把多的颜色全都分到叶子节点即可,这样在菊花图的情况下最长也只有 \(3\) 的长度。

点击查看代码
#include<bits/stdc++.h>
using namespace  std;
#define endl '\n'
#define int long long
const int N=3e5+3;
#define int long long

void solve() {
    int n;
    cin >> n;
    n = n * 2;
    vector<int> g[n + 1];
    for (int i = 0; i < n - 1; ++i) {
        int x, y;
        cin >> x >> y;
        g[x].push_back(y);
        g[y].push_back(x);
    }
    vector<int> a(n + 3);
    function<void(int u, int fa, int ls)> dfs = [&](int u, int fa, int ls) {
        a[u] = ls;
        for (auto v: g[u]) {
            if (v == fa)continue;
            dfs(v, u, ls ^ 1);
        }
    };
    dfs(1, 0, 0);
    array<int, 2> cnt={0,0};
    for (int i = 1; i <= n; ++i) {
        cnt[a[i]]++;
    }
    for (int i = 1; i <= n; ++i) {
        if (cnt[0] == cnt[1])continue;
        if (cnt[0] > cnt[1]) {
            if (g[i].size() == 1) {
                if (a[i] == 0) {
                    a[i] = 1;
                    cnt[0]--;
                    cnt[1]++;
                }
            }
        } else {
            if (g[i].size() == 1) {
                if (a[i] == 1) {
                    a[i] = 0;
                    cnt[1]--;
                    cnt[0]++;
                }
            }
        }
    }
    for (int i = 1; i <=n ; ++i) {
        cout<<a[i]<<" \n"[i==n];
    }
}

signed main(){
    ios::sync_with_stdio(false),cin.tie(0);
    int t=1;
    cin>>t;
    while (t--){
        solve();
    }
}

  1. https://qoj.ac/download.php?type=attachments&id=1894&r=1 ↩︎

posted @ 2025-09-24 13:39  Ke_scholar  阅读(16)  评论(0)    收藏  举报