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();
}
}

浙公网安备 33010602011771号