<center> <h1> week of 12/12 </h1>
here we go...
</center>
---
### `📝 notes`
USACO returns this friday.
---
## contest reflection ([cf round #837](https://codeforces.cc/contest/1771))
### performance:
horrible, i solved the first two problems, which were incredibly standard in the first 10 minutes. but died on implementation for p2 for the next hour.
if i was more focused on debugging problem 2, i could have probably solved problem 3.
nonetheless, it was enough to promote to the Pupil rank in CodeForces.
Which, for just participating in only $5$ contests, is just alright.
### problems:
#### hossam and combinatorics (https://codeforces.cc/contest/1771/problem/A)
simply find occurences of the min & max, and do $2 \cdot (\text{min} \cdot \text{max})$, if all elements are the same, do $n \cdot (n - 1)$.
remember to use long longs to avoid overflow.
```cpp=
#include "bits/stdc++.h"
using namespace std;
using ll = long long;
#define all(x) begin(x), end(x)
#define rall(x) x.rbegin(), x.rend()
#define sz(x) (int)(x.size())
#define inf 1000000010
#define linf 0x3f3f3f3f3f3f3f3f
#define endl "\n"
#define f first
#define s second
#define pi pair<int, int>
#ifdef LOCAL
#include "/mnt/c/yukon/dbg.cpp"
#else
#define dbg(...) 0
#endif
#define int ll
template <typename T>
ostream& operator<<(ostream& os, const vector<T>& v) {
for (int i = 0; i < sz(v); ++i) {
os << v[i] << ' ';
}
return os;
}
void solve() {
int n;
cin >> n;
vector<int> a(n);
map<int, int> occ;
for (int i = 0; i < n; i++) {
cin >> a[i];
occ[a[i]]++;
}
bool same = 1;
for (int i = 1; i < n; i++) {
if (a[i] != a[i - 1]) same = 0;
}
if (same) {
cout << (n * (n - 1)) << endl;
return;
}
sort(all(a));
cout << (occ[a[0]] * occ[a.back()]) * 2 << endl;
}
signed main() {
cin.tie(0)->sync_with_stdio(0);
int tc;
cin >> tc;
for (int _ = 0; _ < tc; _++) {
solve();
#ifdef LOCAL
cout << "____________________" << endl;
#endif
}
}
// don't get stuck on one approach
// question bounds
// flesh out your approach before implementing o.o
```
#### hossam and friends (https://codeforces.cc/contest/1771/problem/B)
we'll count subsegments, by the number of subsegments starting at $i$ for all $i$.
the longest we can go is, the min of all friends from $i \dots n$. we can precalculate a suffix array for this.
```cpp=
#include "bits/stdc++.h"
using namespace std;
using ll = long long;
#define all(x) begin(x), end(x)
#define rall(x) x.rbegin(), x.rend()
#define sz(x) (int)(x.size())
#define inf 1000000010
#define linf 0x3f3f3f3f3f3f3f3f
#define endl "\n"
#define f first
#define s second
#define pi pair<int, int>
#ifdef LOCAL
#include "/mnt/c/yukon/dbg.cpp"
#else
#define dbg(...) 0
#endif
#define int ll
template <typename T>
ostream& operator<<(ostream& os, const vector<T>& v) {
for (int i = 0; i < sz(v); ++i) {
os << v[i] << ' ';
}
return os;
}
void solve() {
int n, m;
cin >> n >> m;
vector<int> mini(n + 1, inf);
for (int i = 0; i < m; i++) {
int u, v;
cin >> u >> v;
if (u > v) swap(u, v);
mini[u] = min(mini[u], v);
}
vector<int> back(n + 2, inf);
for (int i = n; ~i; --i) {
back[i] = min(back[i + 1], mini[i]);
}
int ans = 0;
for (int i = 1; i < n; i++) {
int len = back[i] - i - 1;
if (back[i] == inf) {
len = (n + 1) - i - 1;
}
// cout << i << ' ' << len << endl;
// cout << i << ' ' << mini[i] << ' ' << len << endl;
ans += len;
}
cout << ans + n << endl;
}
signed main() {
cin.tie(0)->sync_with_stdio(0);
int tc;
cin >> tc;
for (int _ = 0; _ < tc; _++) {
solve();
#ifdef LOCAL
cout << "____________________" << endl;
#endif
}
}
// don't get stuck on one approach
// question bounds
// flesh out your approach before implementing o.o
```
#### hossam and trainees (https://codeforces.cc/contest/1771/problem/C)
we want to find if any two elements in the array have a $\text{gcd} > 1$.
the elements go up to $10^9$, and a property about the prime factorizations for a large number like $10^9$ is that the degree of a prime $> \sqrt{10^9}$ will only have a degree of one.
so, we'll just calcualate all primes up until $\sqrt{10^9}$, and check for prime factor occurences.
```cpp=
#include "bits/stdc++.h"
using namespace std;
using ll = long long;
#define all(x) begin(x), end(x)
#define rall(x) x.rbegin(), x.rend()
#define sz(x) (int)(x.size())
#define inf 1000000010
#define linf 0x3f3f3f3f3f3f3f3f
#define endl "\n"
#define f first
#define s second
#define pi pair<int, int>
#ifdef LOCAL
#include "/mnt/c/yukon/dbg.cpp"
#else
#define dbg(...) 0
#endif
#define int ll
template <typename T>
ostream& operator<<(ostream& os, const vector<T>& v) {
for (int i = 0; i < sz(v); ++i) {
os << v[i] << ' ';
}
return os;
}
vector<bool> pp(32000 + 1);
vector<int> lst;
void solve() {
int n;
cin >> n;
vector<int> a(n);
map<int, int> occ;
for (int i = 0; i < n; i++) {
cin >> a[i];
for (int j : lst) {
if (a[i] % j == 0) {
if (occ[j] > 0) {
dbg(occ);
cout << "YES" << endl;
for (int k = i + 1; k < n; k++) cin >> a[k];
return;
}
occ[j]++;
}
while (a[i] % j == 0) {
a[i] /= j;
}
}
if (a[i] > 1) {
if (occ[a[i]] > 0) {
dbg(occ);
cout << "YES" << endl;
for (int j = i + 1; j < n; j++) cin >> a[j];
return;
}
occ[a[i]]++;
}
}
cout << "NO" << endl;
}
signed main() {
cin.tie(0)->sync_with_stdio(0);
pp[0] = pp[1] = true;
for (int i = 2; i * i <= (int)(32000); i++) {
if (!pp[i]) {
for (int j = i * i; j <= (int)(32000); j += i) pp[j] = true;
}
}
for (int i = 2; i <= (int)(32000); i++) {
if (!pp[i]) lst.push_back(i);
}
int tc;
cin >> tc;
for (int _ = 0; _ < tc; _++) {
solve();
#ifdef LOCAL
cout << "____________________" << endl;
#endif
}
}
// don't get stuck on one approach
// question bounds
// flesh out your approach before implementing o.o
```
#### [hossam and (sub-)palindromic tree](https://codeforces.cc/contest/1771/problem/D)
Consider storing the answer for some interval in $dp_{l,r}$. Where $l$ and $r$ represent the left and right endpoints in the interval, respectively.
Then, our transitions would be:
$$
dp_{l,r} = \left\{\begin{array}{lr}
dp(l + 1, r - 1) + 2, & s_l = s_r\\
\max(dp_{l+1,r}, dp_{l, r-1}), & s_l \neq s_r\\
\end{array}\right\}
$$
That's pretty simple, especially since we're allotted $\mathcal{O}(n^2)$, the only caveat being that we have to find these intervals on a tree.
In order to process this, we'll compute distances between every pair of nodes.
Then, between two nodes $l, r$. $l + 1$ will simply be the node that's adjacent to $l$ which is closer to $r$ than $l$.
The only special case is if $l = r$, then $dp_{l,r} = 1$.
time complexity: $\mathcal{O}(n^2)$.
```cpp=
#include "bits/stdc++.h"
using namespace std;
using ll = long long;
#define all(x) begin(x), end(x)
#define rall(x) x.rbegin(), x.rend()
#define sz(x) (int)(x.size())
#define inf 1000000010
#define linf 0x3f3f3f3f3f3f3f3f
#define endl "\n"
#define f first
#define s second
#define pi pair<int, int>
#ifdef LOCAL
#include "/mnt/c/yukon/dbg.cpp"
#else
#define dbg(...) 0
#endif
template <typename T>
ostream& operator<<(ostream& os, const vector<T>& v) {
for (int i = 0; i < sz(v); ++i) {
os << v[i] << ' ';
}
return os;
}
void solve() {
int n;
cin >> n;
string s;
cin >> s;
vector<vector<int>> adj(n);
for (int i = 0; i < n - 1; i++) {
int u, v;
cin >> u >> v;
--u;
--v;
adj[u].push_back(v);
adj[v].push_back(u);
}
// first compute distances o(n^2)
vector<vector<int>> dist(n, vector<int>(n));
for (int i = 0; i < n; i++) {
function<void(int u, int par)> dfs = [&](int u, int par) {
for (int v : adj[u]) {
if (v == par) continue;
dist[i][v] = (par == -1 ? 0 : dist[i][u]) + 1;
dfs(v, u);
}
};
dfs(i, -1);
dbg(i, dist[i]);
}
// bfs
vector<vector<int>> dp(n, vector<int>(n, -1));
queue<pi> todo;
for (int i = 0; i < n; i++) todo.push({i, i});
while (!todo.empty()) {
pi top = todo.front();
todo.pop();
if (dp[top.f][top.s] != -1) continue;
int xmm = -1, ymm = -1;
// <- l, r ->
for (int i : adj[top.f]) {
if (dist[i][top.s] < dist[top.f][top.s]) {
xmm = i;
break;
}
}
for (int i : adj[top.s]) {
if (dist[i][top.f] < dist[top.f][top.s]) {
ymm = i;
break;
}
}
if (top.f == top.s) {
dp[top.f][top.s] = 1;
dp[top.s][top.f] = dp[top.f][top.s];
} else {
dp[top.f][top.s] = max({dp[top.f][top.s], dp[xmm][top.s], dp[top.f][ymm]});
if (s[top.f] == s[top.s]) {
dp[top.f][top.s] = max(dp[top.f][top.s], max(0, dp[xmm][ymm]) + 2);
}
dp[top.s][top.f] = dp[top.f][top.s];
}
for (int i : adj[top.f]) {
if (i != xmm) todo.push({i, top.s});
}
for (int i : adj[top.s]) {
if (i != ymm) todo.push({top.f, i});
}
}
int ans = 1;
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
ans = max(ans, dp[i][j]);
}
}
cout << ans << endl;
}
int main() {
cin.tie(0)->sync_with_stdio(0);
int tc;
cin >> tc;
for (int _ = 0; _ < tc; _++) {
solve();
#ifdef LOCAL
cout << "____________________" << endl;
#endif
}
}
// don't get stuck on one approach
// question bounds
// flesh out your approach before implementing o.o
```
#### hossam and a letter
we have a $400 \times 400$ grid, and we have to find the largest "H" that can be constructed given that it cannot contain any "#"s, and can only contain one "m".
this is another common "construct the largest letter" type of problem.
for this problem, we'll find the maximum height a stick can go up at $(i,j)$ for all $(i, j)$, and also the maximum height going down. we'll also add an extra dimension of size two to dictate whether we've already used our "m."
then, for all $(i, j)$, we'll stem a stick starting at $(i, j)$, and the second one at $(i, j + k)$.
Then, the total amount used is $2(\min(up_{i,j}, up_{i,j+k}) + \min(down_{i,j}, down_{i,j+k})) + k$. If we haven't used the "m" on the horizontal, we'll use it on either the up or the down.
```cpp=
// midsummer madness, i can't take it no more
#include "bits/stdc++.h"
using namespace std;
using ll = long long;
#define all(x) begin(x), end(x)
#define rall(x) x.rbegin(), x.rend()
#define sz(x) (int)(x.size())
#define inf 1000000010
#define linf 0x3f3f3f3f3f3f3f3f
#define endl "\n"
#define f first
#define s second
#define pi pair<int, int>
#ifdef LOCAL
#include "/mnt/c/yukon/dbg.cpp"
#else
#define dbg(...) 0
#endif
template <typename T>
ostream& operator<<(ostream& os, const vector<T>& v) {
for (int i = 0; i < sz(v); ++i) {
os << v[i] << ' ';
}
return os;
}
int main() {
cin.tie(0)->sync_with_stdio(0);
int n, m;
cin >> n >> m;
vector<vector<char>> v(n, vector<char>(m));
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> v[i][j];
}
}
vector<vector<vector<int>>> up(n, vector<vector<int>>(m, vector<int>(2)));
vector<vector<vector<int>>> down(n, vector<vector<int>>(m, vector<int>(2)));
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
// vertical line stemming from (i, j)
// up
int pp = i - 1;
int md = 0;
while (~pp) {
if (v[pp][j] == 'm') md++;
if (v[pp][j] == '#') break;
if (md > 1) break;
up[i][j][1] = max(up[i][j][1], i - pp);
if (md == 0) {
up[i][j][0] = max(up[i][j][0], i - pp);
}
pp--;
}
pp = i + 1;
md = 0;
while (pp < n) {
if (v[pp][j] == 'm') md++;
if (v[pp][j] == '#') break;
if (md > 1) break;
down[i][j][1] = max(down[i][j][1], pp - i);
if (md == 0) {
down[i][j][0] = max(down[i][j][0], pp - i);
}
pp++;
}
}
}
int ans = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j + 2 < m; j++) {
// draw line starting from (i, j)
if (v[i][j] == '#' || v[i][j + 1] == '#') continue;
int md = (v[i][j] == 'm') + (v[i][j + 1] == 'm');
// extend rightward
for (int k = j + 2; k < m; k++) {
if (v[i][k] == 'm') md++;
if (v[i][k] == '#') break;
if (md > 1) break;
// use md up, down, or center
if (md == 1) {
// force
int mup = min(up[i][j][0], up[i][k][0]);
int mdown = min(down[i][j][0], down[i][k][0]);
if (mup && mdown) {
ans = max(
ans,
2 * (mup + mdown) + (k - j + 1));
}
} else {
// up
int fs = max(min(up[i][j][0], up[i][k][1]), min(up[i][j][1], up[i][k][0]));
int mdown = min(down[i][j][0], down[i][k][0]);
if (fs && mdown) {
ans = max(
ans,
2 * (fs + mdown) + (k - j + 1));
}
dbg(ans, i, k);
// down
int mup = min(up[i][j][0], up[i][k][0]);
fs = max(min(down[i][j][0], down[i][k][1]), min(down[i][j][1], down[i][k][0]));
if (mup && fs) {
ans = max(
ans,
2 * (fs + mup) + (k - j + 1));
}
}
}
}
}
cout << ans << endl;
}
// don't get stuck on one approach
// question bounds
// flesh out your approach before implementing o.o
```
#### lucky chains
here, we have to find the longest "lucky" chain that starts with $a, b$.
a lucky chain is described a chain of $(a,b), (a+1, b+1), (a+2, b+2), \dots, (a+k, b+k)$, where all pairs $a, b$ have a GCD of $1$.
Answer $n \leq 10^6$ queries.
##### `solution`
wlog assume that $b > a$,
remember that the idea behind Euclid's GCD Algorithm relies on the fact that $\gcd(a, b) = \gcd(a, b-a)$.
thus, $\gcd(a+k,b+k) = \gcd(b - a, a + k)$.
we just have to find the smallest $k$.
obviously, $a + k \equiv 0 \pmod{d}$, where $d$ is a divisor of $b - a$. (actually we only need to consider prime factors).
and so, we'll just find the closest multiple of $d$ greater than $a + k$, and subtract $a$.
There are at most $\log_2(n)$ prime divisors of $n$.
We'll calculate this with eratosthenes' sieve and
slightly alter it to store the maximum prime divisor.
Also if $b-a = 1$, then the answer is $-1$, since it can be extended infinitely.
```cpp=
#include "bits/stdc++.h"
using namespace std;
using ll = long long;
#define all(x) begin(x), end(x)
#define rall(x) x.rbegin(), x.rend()
#define sz(x) (int)(x.size())
#define inf 1000000010
#define linf 0x3f3f3f3f3f3f3f3f
#define endl "\n"
#define f first
#define s second
#define pi pair<int, int>
#ifdef LOCAL
#include "/mnt/c/yukon/dbg.cpp"
#else
#define dbg(...) 0
#endif
template <typename T>
ostream& operator<<(ostream& os, const vector<T>& v) {
for (int i = 0; i < sz(v); ++i) {
os << v[i] << ' ';
}
return os;
}
vector<int> isp(1e7 + 1, -1);
void solve() {
int a, b;
cin >> a >> b;
if (__gcd(a, b) > 1) {
cout << 0 << endl;
} else if (a % 2 && b % 2) {
cout << 1 << endl;
} else if (abs(a - b) == 1) {
cout << -1 << endl;
} else {
int dd = abs(a - b);
ll ans = inf;
while (isp[dd] != -1) {
ll mlt = ((a + isp[dd] - 1) / isp[dd]) * isp[dd];
ans = min(ans, mlt - a);
dd /= isp[dd];
}
cout << ans << endl;
}
}
int main() {
cin.tie(0)->sync_with_stdio(0);
for (int i = 2; i <= (int)(1e7); i++) {
if (isp[i] == -1) {
for (int j = i; j <= (int)(1e7); j += i) {
if (isp[j] == -1) isp[j] = i;
}
}
}
int tc;
cin >> tc;
for (int _ = 0; _ < tc; _++) {
solve();
#ifdef LOCAL
cout << "____________________" << endl;
#endif
}
}
// don't get stuck on one approach
// question bounds
// flesh out your approach before implementing o.o
```
alright, im gonna start the December USACO Contest now.
GLHF!