Invitational and Addendum: Zhengzhou, Kunming, HDU, and Luogu
Primarily based on original solution records, including Zhengzhou Invitational, Kunming Invitational, HDU 2973, and Luogu B3645.
Scope of Inclusion#
2024 Zhengzhou Invitational M2024 Zhengzhou Invitational H2024 Zhengzhou Invitational A2024 Zhengzhou Invitational D2024 Kunming Invitational A2024 Kunming Invitational EHDU 2973Luogu B3645
2024 Zhengzhou Invitational M - Effective Algorithm#
Given a sequence of positive integers and of length . For each , perform exactly one of the following operations:
- Change to any integer that satisfies .
Please find the smallest non-negative integer such that there exists at least one method to make all numbers in the sequence equal after the operations.
This is clearly a binary search problem. If the range of possible values for for all elements has an intersection, then such a exists; otherwise, it does not.
#define int long long
void solve() {
int n;cin >> n;
vector<int> a(n + 1), b(n + 1);
for (int i = 1;i <= n;i++)cin >> a[i];
for (int i = 1;i <= n;i++)cin >> b[i];
int l = 0, r = 1e9;
while (l < r) {
int mid = l + r >> 1;
int x = 1, y = 1e18;
for (int i = 1;i <= n;i++) {
x = max(x, a[i] - mid * b[i]);
y = min(y, a[i] + mid * b[i]);
}
if (x > y)l = mid + 1;
else r = mid;
}
cout << l << '\n';
}cpp2024 Zhengzhou Invitational H - Random Stack#
Toxel obtained a random “stack.” This stack can be considered a multiset . When an element is taken from a non-empty random stack , any element in the set has an equal probability of being taken. After the element is taken, it is removed from the set. For example, with , there is a probability of taking 1, leaving the set as , and a probability of taking 2, leaving the set as . Each element removal event is independent.
Toxel is performing some operations on this set. Initially, the set is empty. It performs a total of operations, of which are insertions and are removals. Now, Toxel tells you the sequence of operations and the numbers inserted each time, ensuring that the set is non-empty each time a removal occurs. Toxel wants to know, if the numbers taken out each time are arranged into a sequence, what is the probability that this sequence is non-decreasing?
Here, the strict definition of non-decreasing is: each element of the taken-out sequence (except the last) is less than or equal to its subsequent element.
Since the answer may not be an integer, you only need to output this value modulo .
That is, .
Different from the official approach, this uses a multiset for convenience.
#define int long long
constexpr int mod = 998244353;
int inv(int a, int b = mod - 2) {
int ans = 1;
while (b) {
if (b & 1)ans = (ans * a) % mod;
a = (a * a) % mod;b >>= 1;
}
return ans;
}
void solve() {
int n;cin >> n;
multiset<int>s;
int p = 1, q = 1;
int mx = -1;
map<int, int>mp;
for (int i = 1;i <= 2 * n;i++) {
int x;cin >> x;
if (x >= 0) {
if (x < mx) {
cout << "0\n";exit(0);
}
s.insert(x);mp[x]++;
} else {
int cnt = mp[*s.begin()];
p = (p * cnt) % mod;
q = (q * s.size()) % mod;
mx = max(mx, *s.begin());
mp[*s.begin()]--;
s.erase(s.begin());
}
}
cout << p * inv(q) % mod << '\n';
}cpp2024 Zhengzhou Invitational A - Once In My Life#
For little A, positive integers whose digits include and have at least two digits equal to are considered lucky numbers.
When , obviously is a lucky number for little A, but is not a lucky number because the digit appears only once, and is not a lucky number because digits are missing.
Now little A has a positive integer and a positive integer . He wants to find a positive integer such that their product is a lucky number. Can you use a computer to help him compute ?
Construction.
According to the official solution:
cout << ((1234567890 + d) * (int)pow(10, ceil(log10(n))) + n - 1) / n << '\n';cppThe code here was written hastily and may cause issues; you can compute by multiplying step by step to avoid precision loss.
2024 Zhengzhou Invitational D - Ratio of Distances#
Given distinct points in the plane (subscript 1 represents Manhattan distance - , subscript 2 represents Euclidean distance - ).
Find:
Simple mathematics:
2024CCPC Zhengzhou Invitational and Henan Provincial Competition (A,B,C,D,F,G,H,J,K,L,M) ↗
Let . After simplification,
When , the maximum is achieved. Then
Removing the absolute value yields
Thus, sort by and respectively, and take the maximum among them.
#define int long long
void solve() {
int n;cin >> n;
vector<pair<int, int>> p(n);
for (int i = 0;i < n;i++)cin >> p[i].first >> p[i].second;
sort(p.begin(), p.end(), [](auto x, auto y) {
return x.first + x.second < y.first + y.second;
});
double ans = 1;
for (int i = 1;i < n;i++) {
auto [x2, y2] = p[i];
auto [x1, y1] = p[i - 1];
ans = max(ans, (abs(x1 - x2) + abs(y1 - y2)) / hypot(x1 - x2, y1 - y2));
}
sort(p.begin(), p.end(), [](auto x, auto y) {
return x.first - x.second < y.first - y.second;
});
for (int i = 1;i < n;i++) {
auto [x2, y2] = p[i];
auto [x1, y1] = p[i - 1];
ans = max(ans, (abs(x1 - x2) + abs(y1 - y2)) / hypot(x1 - x2, y1 - y2));
}
cout << fixed << setprecision(15) << ans << '\n';
}cpp2024 Kunming Invitational A - Two-Star Competition#
For some reason, education experts are preparing to rate competitions. The experts have already determined the rating outcome for each competition, where the -th competition is rated as stars.
It is said that each competition is rated based on attributes, where the -th attribute of the -th competition is denoted as , and each attribute ranges from 0 to (inclusive). The score of a competition is the sum of all its attributes. That is, let represent the score of the -th competition, we have .
It seems natural that a higher-star competition should have a higher score. The experts require that for any two competitions , if , then must hold. Unfortunately, the experts forgot to collect some (or even all) attribute data for some competitions. As the expert’s assistant, you are tasked with filling in these missing attribute values so that the above constraint holds for any two competitions.
Greedy from smallest to largest, note a trick: how to restore the indices? sort in reverse order.
#define int long long
void solve() {
int n, m, k;cin >> n >> m >> k;
vector<int> s(n + 1);
vector<vector<int>> v(n + 1, vector<int>(m + 4));
for (int i = 1;i <= n;i++) {
cin >> s[i];v[i][0] = s[i];
int sum = 0, cnt = 0;
for (int j = 1;j <= m;j++) {
cin >> v[i][j];
if (v[i][j] != -1) {
sum += v[i][j];
} else {
cnt++;
}
}
v[i][m + 1] = sum;
v[i][m + 2] = cnt;
v[i][m + 3] = i;
}
sort(v.begin(), v.end(), [](auto x, auto y) {
return x[0] < y[0];
});
int last = -1, cur = -1;
for (int i = 1;i <= n;i++) {
if (v[i][0] != v[i - 1][0]) {
last = cur;
}
int x = v[i][m + 1] - last - 1;
if (x >= 0) {
for (int j = 1;j <= m;j++) {
if (v[i][j] == -1) {
v[i][j] = 0;
}
}
} else {
x = -x;
if (v[i][m + 2] * k + v[i][m + 1] <= last) {
cout << "No\n";return;
}
for (int j = 1;j <= m;j++) {
if (v[i][j] == -1) {
v[i][j] = min(k, x);
x -= v[i][j];
}
}
}
int sum = 0;
for (int j = 1;j <= m;j++) {
sum += v[i][j];
}
cur = max(cur, sum);
}
cout << "Yes\n";
sort(v.begin(), v.end(), [&](auto x, auto y) {
return x[m + 3] < y[m + 3];
});
for (int i = 1;i <= n;i++) {
for (int j = 1;j <= m;j++) {
cout << v[i][j] << " \n"[j == m];
}
}
}cpp2024 Kunming Invitational E - Learn and Practice#
Given a sequence of positive integers of length and a non-negative integer , you can perform the following operation at most once:
Choose two integers and such that , then for each , change to .
That is, add to the entire interval , aiming to maximize the greatest common divisor of the entire sequence.
Difference idea + thinking.
Brute force: This problem only involves two indices in the difference array. Using pure difference, you only need to enumerate two indices in the difference array. However, the time complexity is , which will definitely time out.
void solve() {
int n, k;cin >> n >> k;
vector<int> a(n + 1), dif(n + 2);
int ans = a[1];
for (int i = 1;i <= n;i++)cin >> a[i], ans = __gcd(ans, a[i]);
for (int i = 1;i <= n;i++)dif[i] = a[i] - a[i - 1];
for (int i = 1;i <= n;i++) {
for (int j = i;j <= n;j++) {
dif[i] += k;dif[j + 1] -= k;
int res = dif[1];
for (int k = 1;k <= n;k++) {
res = __gcd(dif[k], res);
}
ans = max(ans, abs(res));
dif[i] -= k;dif[j + 1] += k;
}
}
cout << ans << '\n';
}cppSolution: This problem can divide into 4 parts:
The answer is the gcd of these four numbers: .
The number of points where the prefix and suffix gcd change compared to the previous result is small, so enumerate them sequentially.
There is more than one method; the key is to realize the characteristic that the number of points where the gcd changes is small.
#define int long long
void solve() {
int n, k;cin >> n >> k;
vector<int> a(n + 1);
for (int i = 1;i <= n;i++)cin >> a[i];
if (n == 1) {
cout << k + a[1] << '\n';return;
}
unordered_set<int>s1, s2;
s1.insert(1);
s2.insert(n);
int g = a[1];
for (int i = 1;i <= n;i++) {
int gg = g;
g = __gcd(g, a[i]);
if (gg != g) {
s1.insert(i);
}
}
g = a[n];
for (int i = n;i >= 1;i--) {
int gg = g;
g = __gcd(g, a[i]);
if (gg != g) {
s2.insert(i);
}
}
vector<int> pre(n + 1), suf(n + 1);
pre[1] = a[1];suf[n] = a[n];
for (int i = 2;i <= n;i++) {
pre[i] = __gcd(pre[i - 1], a[i]);
}
for (int i = n - 1;i >= 1;i--) {
suf[i] = __gcd(suf[i + 1], a[i]);
}
int ans = pre[n];
for (auto l : s1) {
for (auto r : s2) {
if (l <= r) {
int x = __gcd(pre[l - 1], suf[r + 1]);
if (l == 1) {
x = suf[r + 1];
}
if (r == n) {
x = pre[l - 1];
}
int res = l != r ? abs(a[l] - a[l + 1]) : a[r] + k;
for (int i = l + 1;i <= r - 1;i++) {
res = __gcd(res, abs(a[i] - a[i + 1]));
}
int y = __gcd(res, a[r] + k);
if (l == 1 && r == n) {
x = y;
}
ans = max(ans, __gcd(x, y));
}
}
}
cout << ans << '\n';
}cppHDU 2973#
Wilson’s Theorem
Given , compute
Idea: Easily think of Wilson’s Theorem ↗
- If is prime, then
It’s easy to see
Then
- If is not prime, then (by the corollary of Wilson’s Theorem)
Let ,
Therefore
Consider sieve method ↗: prime sieve.
#include <iostream>
const int M = 1e6 + 5, N = 3 * M + 7;
bool not_prime[N];
int sum[M];
int main() {
for (int i = 2; i < N; ++i)
if (!not_prime[i])
for (int j = 2; j * i < N; ++j)
not_prime[j * i] = 1;
for (int i = 1; i < M; ++i)
sum[i] = sum[i - 1] + !not_prime[3 * i + 7];
int t;
std::cin >> t;
while (t--) {
int n;
std::cin >> n;
std::cout << sum[n] << std::endl;
}
}
cppLuogu B3645 - Sequence Prefix Sum 2#
B3645 Sequence Prefix Sum 2 - Luogu ↗ B 3645 Sequence Prefix Sum 2 Solution - lrqlrq250’s Blog - Luogu Blog ↗

is found to be equivalent to
Then the answer is , where is the multiplicative inverse of modulo .
That is, ,
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll p = 1145141;
int n, q;
ll a[1000010],inv[1200010],s[1000010];
int main()
{
ios::sync_with_stdio(0), cin.tie(nullptr);
s[0] = inv[1] = 1;
cin >>n >> q;
for (int i = 1; i <= n;i++) cin >> a[i];
for (int i = 1; i <= n;i++) s[i] = s[i - 1] * a[i] % p;//prefix product s[i]
for (int i = 2; i <= p; i++)//up to p, not n!!!
inv[i] = (p - p / i) * inv[p % i] % p;
ll ans = 0;
while(q--)
{
int l, r;
cin >> l >> r;
ans ^= s[r] * inv[s[l-1]] % p;
}
cout << ans << '\n';
}cpp