Nowcoder Solutions: Winter Contests, Weeklies, and Multi-School
December 2023 to August 2024, primarily based on original solution records, covering bookmarked winter contests, weekly contests, and multi-school problems.
Scope of Inclusion#
Winter Break 2 - I/JWinter Break 2 - DWinter Break 3 - L/MWinter Break 3 - G/HWinter Break 5 - G/HNowcoder Multi-University Training 4 - HNowcoder Multi-University Training 4 - CNowcoder Weekly Contest 60 - DNowcoder Weekly Contest 60 - ENowcoder Weekly Contest 60 - FNowcoder Weekly Contest 51 - DNowcoder Weekly Contest 51 - ENowcoder Weekly Contest 51 - FNowcoder Weekly Contest 31 - ENowcoder Weekly Contest 52 - CNowcoder Weekly Contest 52 - ENowcoder Weekly Contest 52 - FNowcoder Weekly Contest 47 - DNowcoder Weekly Contest 47 - ENowcoder Weekly Contest 47 - FNowcoder Weekly Contest 35 - F/GNowcoder Weekly Contest 55 - E
2024 Nowcoder Winter Break Algorithm Basic Training Camp 2 - I/J Tokitsukaze and Short Path (plus)(minus)#
The only difference between plus and minus is the way the edge weight is calculated.
Tokitsukaze has a complete graph G with n vertices, numbered 1 to n. The value of the vertex numbered i is .
A complete graph refers to a graph where there is exactly one undirected edge between every pair of vertices. For the undirected edge between vertex u and vertex v, the edge weight is calculated as follows:
Define ) as the shortest path distance from vertex to vertex . Find
Regarding the definition of the shortest path:
Define a path from s to t as a sequence of several end-to-end edges such that the first edge starts at s and the last edge ends at t. Specifically, when s=t, the sequence can be empty.
Define the length of a path from s to t as the sum of the edge weights on that path.
Define the shortest path from s to t as the minimum length among all paths from s to t.
At first glance, this seems like a graph theory problem, but it definitely won’t be solved using graph theory methods.
Solution#
I (plus)#
According to the problem statement:
- The shortest path must go through directly connected nodes; otherwise, the result will definitely be larger.
- If
a[u]>a[v], then . Otherwise, .
If the array is sorted, then a[i]<=a[j] always holds, and we only need to add 2*a[j].
The form of the answer is:
for i (0, n - 1)
for j (i + 1, n - 1)
ans += 2 * a[j]
ans *= 2pythoncnt = pre[n - 1]
for i (0, n - 2)
ans += cnt - pre[i]pythonfor(int i = 2, j = 1; i <= n; i ++, j ++)
ans += w[i] * 2 * j;cppvoid solve() {
int n;
cin >> n;
vector<ll> a(n), pre(n);
ll r1 = 0;
for (int i = 0; i < n; i++) {
cin >> a[i];
r1 += a[i];
}
sort(a.begin(), a.end());
pre[0] = a[0];
for (int i = 1;i < n;i++) {
pre[i] = pre[i - 1] + a[i];
}
ll ans = 0;
for (int i = 1;i < n;i++) {
ans += r1 - pre[i - 1];
}
cout << ans * 4 << '\n';
}cppJ (minus)#
The main problem is to find the shortest path. There are only two possibilities: a[i-1] * 2 || 4 * a[0]
Brute force approach:
ll ans = 2 * a[0] * (n - 1);
for (int i = 1;i < n;i++) {
for (int j = i + 1;j < n;j++) {
ans += min(2 * a[i], 4 * a[0]);
}
}
cout << ans * 2 << '\n';cppCorrect solution:
void solve() {
int n;
cin >> n;
vector<ll> a(n);
for (int i = 0;i < n;i++)
cin >> a[i];
sort(a.begin(), a.end());
ll ans = 2 * a[0] * (n - 1);
for (int i = 1;i < n;i++) {
ans += min(2 * a[i], 4 * a[0]) * (n - i - 1);
}
cout << ans * 2 << '\n';
}cpp2024 Nowcoder Winter Break Algorithm Basic Training Camp 2 - D Tokitsukaze and Slash Draw#
Tokitsukaze’s deck has cards. She already knows that the card “One Shot Kill! Iai Draw” is the -th card from the bottom of the deck. She selects types of cards that can adjust the order of the cards in the deck. The effect of the -th type of card is: take the top cards from the deck and put them at the bottom in order. This effect can be understood as: first take out one card, then put this card at the bottom, repeat this action times. To activate the effect of the -th type of card, you need to pay a of .
Tokitsukaze can perform operations such that each type of card can be activated an unlimited number of times. Can she make the card “One Shot Kill! Iai Draw” appear at the top of the deck? If yes, output the minimum required. If not, output -1.
Solution#
DP | dijkstra (Congruence Shortest Path Model)
represents, under the condition of mod n, the minimum to move the target card up by steps.
(Didn’t quite understand )
const int maxn = 3e5 + 10;
int a[maxn], b[maxn];
ll mn[maxn], dp[5010][5010];
void solve() {
int n, m, k;
cin >> n >> m >> k;
for (int i = 1; i <= n; i++) {
mn[i] = 1e18;
}
for (int i = 1; i <= m; i++) {
cin >> a[i] >> b[i];
for (int j = 1; j <= n; j++) {
int nxt = j * a[i] % n; // Indicates that multiples of a[i] can be flipped
if (!nxt) nxt = n; // Can be commented out?
mn[nxt] = min(mn[nxt], 1ll * j * b[i]); // Represents the cost when it's a multiple of a[i]
}
}
for (int i = 1; i <= n; i++) {
if (i == k) {
dp[0][i] = 0;
} else {
dp[0][i] = 1e18;
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
dp[i][j] = dp[i - 1][j];
}
for (int j = 1; j <= n; j++) {
int nxt = (j + i) % n;
if (!nxt) nxt = n;
dp[i][nxt] = min(dp[i][nxt], dp[i - 1][j] + mn[i]);
}
}
if (dp[n][n] == 1e18) {
cout << -1 << '\n';
} else {
cout << dp[n][n] << '\n';
}
}cpp int n, m, k, a[N], b[N];
ll f[N];
ll solve() {
cin >> n >> m >> k;
for (int i = 0; i < m; i ++) cin >> a[i] >> b[i];
memset(f, -1, sizeof f);
f[k - 1] = 0;
queue<int> q;
q.push(k - 1);
while (!q.empty()) {
auto u = q.front();
q.pop();
for (int i = 0; i < m; i ++) {
int v = (u + a[i]) % n;
if (f[v] != -1 && f[v] <= f[u] + b[i]) continue;
f[v] = f[u] + b[i];
q.push(v);
}
}
return f[n - 1];
}cpp
void solve() {
int n, m, k;
cin >> n >> m >> k;
vector<ll> a(m+1), b(m+1), d(n+1, INTMAX_MAX);
vector<bool> vis(n+1, 0);
for (int i = 1;i <= m;i++)cin >> a[i] >> b[i];
priority_queue<pair<ll, ll>> q;
q.push({ 0,0 });
d[0] = 0;
while (q.size()) {
ll u = q.top().second; q.pop();
if (vis[u])continue;
vis[u] = true;
for (int i = 1;i <= m;i++) {
ll v = (u + a[i]) % n;
if (d[v] > d[u] + b[i]) {
d[v] = d[u] + b[i];
if (!vis[v])q.push({ -d[v], v });
}
}
}
if (d[n - k] == INTMAX_MAX)d[n - k] = -1;
cout << d[n - k] << '\n';
}cpp2024 Nowcoder Winter Break Algorithm Basic Training Camp 3 - L/M Zhinai’s 36 Multiples (easy)(normal)#
Define the operation as concatenating two positive integers literally from left to right.
Zhinai now has a positive integer array of size , with the -th element being . He wants to select two positive integers and concatenate them (front to back) so that the concatenated number is a multiple of . How many feasible schemes does Zhinai have?
She wants to know how many ordered pairs satisfy that is a multiple of .
easy:normal:
#
Method 1: Brute force enumeration
stoi: i.e., string to int
void solve() {
int n;
cin >> n;
vector<int> a(n);
for (int i = 0;i < n;i++) {
cin >> a[i];
}
int cnt = 0;
for (int i = 0;i < n;i++) {
for (int j = 0;j < n;j++) {
if (i != j) {
string s = to_string(a[i]) + to_string(a[j]);
int num = stoi(s);
if (num % 36 == 0) {
cnt++;
}
}
}
}
cout << cnt << '\n';
}cppMethod 2: Just count 36, 72, 108.
void solve() {
int n, x;
cin >> n;
vector<int> a(11);
for (int i = 1;i <= n;++i) {
cin >> x;
a[x]++;
}
cout << a[3] * a[6] + a[7] * a[2] + a[10] * a[8] << '\n';
}cpp#
Method 1: Consider that 36 is actually a multiple of 4 and a multiple of 9.
- A multiple of 4 only needs the last two digits to be divisible by 4.
- A multiple of 9 only needs the sum of all digits to be divisible by 9.
If we continue with this idea, it essentially involves counting whether “it can form a multiple of 4” and “the digit sum can form a multiple of 9” separately, and then doing case analysis; however, for this problem, the bucket counting method that follows is more straightforward and suitable for code implementation.
Method 2: Based on the property of modulus, the result of summing two numbers modulo 36 is actually the sum of each part modulo 36, then modulo 36 again.
That is, .
So we can directly use buckets to count the remainder of each number modulo 36. Also, 36 has a special property: , so we only need to know if it’s a 10-digit number.
(where is the number of digits in )
If
If
is (j * (i < 10LL ? 10LL : 28LL) + i). Here, is the result of a[i] , is a[i], and represents the count of numbers where yields the same result (proving that these numbers differ by multiples of 36, which does not affect the result; they cancel out in , allowing them to be added together to reduce complexity).
For each element in a[i], iterate through . If it is divisible by 36, add it.
void solve() {
int n;
ll ans = 0;
cin >> n;
vector<ll> a(n);
for (int i = 0; i < n; ++i) {
cin >> a[i];
}
auto calc = [&]() {
ll ans = 0;
vector<ll> sum(36, 0);
for (auto i : a) {
for (int j = 0; j < 36; ++j) {
if ((j * (i < 10LL ? 10LL : 28LL) + i) % 36 == 0) {
ans += sum[j];
}
}
sum[i % 36]++;
}
return ans;
};
ans += calc();
reverse(a.begin(), a.end());
ans += calc();
cout << ans << '\n';
}cppI didn’t quite understand the code. My main idea was to preprocess the array, and then in a double loop, ensure that the indices corresponding to the double loop are not the same (i.e., cannot concatenate with itself), so there would be no need to reverse the array and do it again.
void solve() {
int n;
ll ans = 0;
cin >> n;
vector<ll> a(n);
for (int i = 0; i < n; ++i) {
cin >> a[i];
}
vector<ll> sum(36, 0);
for (auto i : a) {
sum[i % 36]++;
}
for (auto i : a) {
--sum[i % 36];
for (int j = 0; j < 36; ++j) {
if ((j * (i < 10LL ? 10LL : 28LL) + i) % 36 == 0) {
ans += sum[j];
}
}
++sum[i % 36];
}
cout << ans << '\n';
}cpp2024 Nowcoder Winter Break Algorithm Basic Training Camp 3 - G/H Zhinai’s Comparison Function (easy)(normal)#
:
There are integer variables . Given sets of values, determine if there is a contradiction.
easy:normal:
#
void solve() {
int n; cin >> n;
bool ok = true;
int xx, yy, zz, x, y, z;
for (int i = 1;i <= n;i++) {
cin >> x >> y >> z;
if (i == 1) {
xx = x, yy = y, zz = z;
}
if (x == y && z) {
ok = false;
}
}
if (n == 2) {
if (xx == x && yy == y && zz != z) {
ok = false;
}
if (xx == y && yy == x && zz == z) {
if (z == 1) {
ok = false;
}
}
}
if (ok) {
cout << "Yes\n";
} else {
cout << "No\n";
}
}cpp#
Enumerate . If there exists a case where , then a contradiction occurs.
If a condition that satisfies the requirements is found, it exists.
The code feels very simple, it’s just that I didn’t think of it myself.
int i, j, k, n, m, t, a[1005];
vector<tuple<int, int, int> > v;
bool fuck() {
for (auto [x, y, w] : v) {
if (w == 1) {
if (a[x] < a[y])continue;
else return 0;
} else {
if (a[x] >= a[y])continue;
else return 0;
}
}
return 1;
}
void solve() {
int n;
cin >> n;
while (n--) {
cin >> i >> j >> k;
v.push_back({ i,j,k });
}
int res = 0;
for (i = 1;i <= 3;i++)
for (j = 1;j <= 3;j++)
for (k = 1;k <= 3;k++) {
a[1] = i; a[2] = j; a[3] = k;
int ans = 0;
res |= fuck();
}
if (res)cout << "Yes\n";
else cout << "No\n";
v.clear();
}cpp2024 Nowcoder Winter Break Algorithm Basic Training Camp 5 - G/H sakiko’s Permutation Construction#
sakiko wants to construct a permutation of length , such that for every is a prime number.
Solution#
Network Flow / Pattern Finding
Found: If , then is , each term being
For , if , then
For , if , then
Found: If
If
For even If we can ensure that are both prime, then we can construct
For odd If we can ensure that are both prime, then we can construct
void solve() {
int n;cin >> n;
auto check = [&](int x) {
for (int i = 2;i * i <= x;i++)
if (x % i == 0)
return 0;
return 1;
};
int a = 1;
if (n % 2) {
cout << "1 ";a++;
}
for (int i = a;i <= n;i++) {
if (check(i + a) && check(i + 1 + n)) {
for (int j = i;j >= a;j--)
cout << j << " ";
for (int j = n;j > i;j--)
cout << j << " ";
cout << '\n';
return;
}
}
for (int i = n;i >= 1;i--)cout << i << " \n"[i == 1];
}cpp2024 Nowcoder Multi-University Training 4 - H Yet Another Origami Problem#
Fried Chicken hates origami problems! Problems that others can solve easily (like CF 1966 E and HDU 6822), he always fails to solve. However, today Fried Chicken is the problem setter! It’s his turn to give the contestants a very difficult origami problem!
Given an array of length , you can perform the following operations any number of times (possibly zero):
Select an index , and then perform one of the following two operations:
- For all such that , let .
- For all such that , let .
Now, you want to minimize the range of the array through these operations. Recall that the range of an array is the difference between the maximum and minimum elements in the array.
Each operation on two numbers essentially does not change the difference between the two numbers. Each time, operate with the second largest and the largest numbers, each time making the largest number move forward, until finally only two numbers remain. The difference between these two numbers is the answer.
Directly take the GCD of all the differences of the sorted array.
As for the proof…
#define int long long
void solve() {
int n;cin >> n;
vector<int> a(n + 1), suf(n);
for (int i = 1;i <= n;i++)cin >> a[i];
sort(a.begin() + 1, a.end());
if (n <= 2) {
if (n == 1) {
cout << "0\n";return;
} else {
cout << abs(a[1] - a[0]) << '\n';return;
}
}
for (int i = 1;i < n;i++)suf[i] = a[i + 1] - a[i];
int g = suf[1];
for (int i = 2;i < n;i++) {
g = __gcd(g, suf[i]);
}
cout << g << '\n';
}cpp2024 Nowcoder Multi-University Training 4 - C Sort 4#
Given a permutation of length . In one operation, you can select no more than 4 elements from the permutation and swap their positions arbitrarily. What is the minimum number of operations required to sort the permutation in ascending order?
According to the problem statement, we know that in each position that is not yet restored, there must be a cycle.
That is, in this permutation, there are several cycles, each independent of the others.
For these cycles, some can be concatenated, some cycles are larger and require multiple operations, and each operation requires 4 moves to restore 3 elements.
void solve() {
int n;cin >> n;
vector<int> p(n + 1);
vector<int> a(n + 1);
for (int i = 1;i <= n;i++) {
cin >> a[i];p[a[i]] = i;
}
vector<int>vis(n + 1), ans;
int cnt = 0;
auto dfs = [&](auto self, int x, int y)->void {
if (vis[x]) {
return;
}
cnt++;vis[x] = 1;
self(self, y, p[y]);
};
for (int i = 1;i <= n;i++)if (p[i] == i)vis[i] = 1;
for (int i = 1;i <= n;i++) {
if (!vis[a[i]]) {
cnt = 0;
dfs(dfs, a[i], p[a[i]]);
ans.push_back(cnt);
}
}
int res = 0;
int c[4] = {};
for (auto x : ans) {
res += x / 3;x %= 3;
c[x]++;
}
cout << c[3] + (c[2] + 1) / 2 + res << '\n';
}cppNowcoder Weekly Contest 60 - D We Are So Awesome#
Today, children are gathered together bragging. Each of them has a certain number of little stars in their hands. For convenience, we represent them as .
Little Waipo bragged, “If we pick a few from among us, the total number of little stars in our hands can represent any positive integer within !”
Little Xiaolong thinks Little Waipo is wrong, but he is a child and cannot calculate.
So Little Xiaolong comes to you for help. He wants you to find the smallest integer that proves Little Waipo is wrong.
Solution#
DP approach
bitset optimized 01 knapsack (almost the same as the problem in swpuOj)
Time complexity: barely passes
void solve() {
int n;cin >> n;
vector<int> a(n + 1);
for (int i = 1;i <= n;i++)cin >> a[i];
bitset<100010> b;
b[0] = 1;
for (int i = 1;i <= n;i++) {
b |= (b << a[i]);
}
for (int i = 1;i <= n;i++) {
if (!b[i]) {
cout << i << '\n';return;
}
}
cout << "Cool!\n";
}cppIf we can already form any number in , what condition must the next number satisfy to be able to form any number in ?
Condition: . When , the number cannot be formed. Otherwise, can definitely form the numbers in the interval together with the previous numbers.
void solve() {
int n;cin >> n;
vector<int> a(n + 1);
for (int i = 1;i <= n;i++)cin >> a[i];
sort(a.begin() + 1, a.end());
int x = 0;
for (int i = 1;i <= n;i++) {
if (a[i] > x + 1 && x < n) {
cout << x + 1 << '\n';return;
}
x += a[i];
}
cout << "Cool!\n";
}cppNowcoder Weekly Contest 60 - E Shuttle Run#
It’s PE class! Today’s activity is the shuttle run. The straight track can be considered a number line. There are points on the track. The teacher placed two poles at points and , called the left pole and the right pole, as the turning points for the shuttle run.
The teacher stipulated that a total of laps must be run today. We consider that starting from one pole and ending at the other pole counts as one lap. Obviously, a total of turns need to be made. suddenly discovered that the poles are movable, so he had a bold idea —
After each run to the right pole and turning back, he must push the right pole to the left for a certain distance (greater than ), but still ensure that the right pole is at an integer point and to the right of the left pole (cannot coincide with the left pole);
After each run to the left pole and turning back, he must push the left pole to the right for a certain distance (greater than ), but still ensure that the left pole is at an integer point and to the left of the right pole (cannot coincide with the right pole);
Now, given the values of integers and , how many different pushing methods does have? Since the answer may be very large, please output the answer modulo . Note that the pole must be pushed at every turn. If it is impossible to push at a certain turn, then that round of pushing is invalid.
Solution#
Actually, it means that in turns, each time you must push at least 1, and the total cannot exceed , i.e., .
1931 (925div3): Review of Combinatorics
Equivalent to having balls placed into boxes (each box must have at least one ball). That is,
So the answer is
The time complexity is , which is too high. So we need another way to solve it.
Introduce , representing how many “balls” are not used. So we have:
So:
That is, there are balls to be placed into boxes (boxes can be empty). How many ways?
Time complexity
Proof that holds
Considering the properties of combinatorial numbers, we know:
Using this property, treating the original equation as an accumulation, it is equivalent to:
Thus, this sum can be recombined and gradually simplified using Pascal’s identity to:
This is a given combinatorial property. From a combinatorial perspective, the combinatorial number on the right, , represents the number of ways to choose elements from elements. The left-hand side, gradually accumulating up to this upper limit, reflects the selection of a specific point as the beginning of the remaining choices, achieving the arrangement that satisfies the conditions through accumulation.
In summary, this equation holds.
void solve() {
int n, m;cin >> n >> m;
cout << C(n - 2, m - 1) << '\n';
}cppNowcoder Weekly Contest 60 - F Stuttering#
wants to say a sentence. This sentence has words. He wants to say them one by one. Unfortunately, stutters:
When saying the st word, the probability that the next word to say advances to the nd word is , and the probability that it remains the st word is .
When saying the th () word, the probability that the next word to say advances to the st word is , the probability that it remains the th word is , and the probability that it retreats to the st word is .
When saying the th word, the speech ends and stops.
Until the speech ends, what is the expected total number of words says?
Solution#
Let represent the expected number of steps to go from . According to the problem statement: (let the three probabilities be )
We have . Substituting gives: ()
Let represent the expected number of steps to go from .
void solve() {
int n;cin >> n;
vector<int> p(n), q(n), e(n);
for (int i = 1;i < n;i++)cin >> p[i];
for (int i = 1;i < n;i++)cin >> q[i];
e[0] = 1;e[1] = (p[1] + q[1]) * inv(p[1]) % mod;
for (int i = 2;i < n;i++) {
e[i] = (q[i] * q[i] % mod * e[i - 1] % mod + (p[i] + q[i]) * (p[i] + q[i]) % mod) % mod * inv(p[i]) % mod * inv(p[i]) % mod;
}
int ans = 0;
for (int i = 0;i < n;i++) {
ans += e[i];ans %= mod;
}
cout << ans << '\n';
}cppOfficial solution:
#define int long long
constexpr int mod = 1e9 + 7;
void solve() {
int n;cin >> n;
vector<int> p(n), q(n);
for (int i = 1;i < n;i++)cin >> p[i];
for (int i = 1;i < n;i++)cin >> q[i];
int P = 1, Q = (p[1] + q[1]) * inv(p[1]) % mod;
p[1] = P, q[1] = Q;
for (int i = 2;i < n;i++) {
int a = p[i], b = q[i];
int mu = (((a * a % mod + b * b % mod) % mod - b * b % mod * P % mod) + mod) % mod;
P = a * a % mod * inv(mu) % mod;
Q = (Q * b % mod * b % mod + (a + b) * (a + b) % mod) % mod * inv(mu) % mod;
p[i] = P, q[i] = Q;
}
vector<int> f(n + 1);
f[n] = 1;
for (int i = n - 1;i >= 1;i--) {
f[i] = p[i] * f[i + 1] % mod + q[i];f[i] %= mod;
}
cout << f[1] << '\n';
}cppNowcoder Weekly Contest 51 - D Little Red’s gcd#
Given two positive integers , output their greatest common divisor .
.
.
Solution#
Large number modulo
Find the gcd of a large number and an int
It’s easy: gcd (a, b)=gcd (b, a%b)
That is, find x=a%b, ans=gcd (b, x)
Using the property: The result of taking the product of multiple consecutive factors modulo p equals the result of taking each factor modulo p, multiplying them, and then taking modulo p again.
That is:
From this property, a can be divided into several blocks, assuming each split is 9 digits (but this seems unnecessary…)
Just calculate digit by digit.
Then
#define int long long
void solve() {
string a;int b;cin >> a >> b;
vector<int> ans;
for (int i = 0;i < a.size();i += 9) {
string s = a.substr(i, 9);
ans.push_back(stoi(s));
}
int x = 0;
for (auto m : ans) {
x *= qpow(10, to_string(m).size(), b);x += m;x %= b;
}
cout << __gcd(x, b) << '\n';
}cpp
#define int long long
void solve() {
string a;int b;cin >> a >> b;
int ans = 0;
for (auto x : a) {
ans = (ans * 10 + x - '0') % b;
}
cout << __gcd(ans, b) << '\n';
}cppNowcoder Weekly Contest 51 - E Little Red Walking Through Matrix#
Given an matrix, each element in the matrix is a positive integer. Little Red is currently at the top-left corner . Each time, she can move from to , , , or , but cannot move outside the matrix. Little Red hopes to find a path to the bottom-right corner . Define the path weight as the maximum value of the points passed along the path. Find the minimum path weight among all paths.
Solution#
BFS + Binary Search
There are many approaches: binary search, shortest path, union-find, but DP is not feasible.
Once you think of binary search, it shouldn’t be difficult! Time complexity . If extended further, this problem can also be understood from the perspective of union-find or shortest path.
constexpr int dx[] = {1, -1, 0, 0};
constexpr int dy[] = {0, 0, 1, -1};
int n,g[505][505];
bool check(int mid) {
if (g[0][0] > mid) return false;
vector<vector<bool>> vis(n, vector<bool>(n, false));
queue<pair<int, int>> q;
q.push({0, 0}); vis[0][0] = true;
while (!q.empty()) {
auto [x, y] = q.front();q.pop();
if (x == n - 1 && y == n - 1) return true;
for (int i = 0; i < 4; ++i) {
int nx = x + dx[i], ny = y + dy[i];
if (nx >= 0 && nx < n && ny >= 0 && ny < n && ! vis[nx][ny] && g[nx][ny] <= mid) {
q.push({nx, ny});
vis[nx][ny] = true;
}
}
}
return false;
}
int main() {
cin >> n;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
cin >> g[i][j];
}
}
int l = INT_MAX, r = INT_MIN;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
l = min(l, g[i][j]);
r = max(r, g[i][j]);
}
}
while (l < r) {
int mid = l + r >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
cout << l << '\n';
}cppUnion-Find approach: Merge in order of increasing weight until (0,0) and (n-1, m-1) are connected.
Nowcoder Weekly Contest 51 - F Little Red’s Array#
Little Red has an array containing numbers .
Little Red has queries. For each query, given an interval , find the maximum absolute value of the sum of a contiguous subarray within the interval. That is, find such that , maximizing .
Solution#
Segment Tree / Mo’s Algorithm / Sparse Table
Information needed for the segment tree:
- Interval sum (sum), maximum subarray sum starting from the left endpoint (lmax), maximum subarray sum ending at the right endpoint (rmax), and maximum subarray sum within the interval (mmax).
- Maximum and minimum values
The problem actually hints: is a contiguous segment, i.e., . The maximum value minus the minimum value of prefix sums within the interval is the answer. So we need to maintain the maximum and minimum values within the interval.
After changing i=1 to i=0, it passed? I don’t understand.
#define int long long
int f1[500010][30], f2[500010][30];
void solve() {
int n;cin >> n;
vector<int> a(n + 1), pre(n + 1);
for (int i = 1;i <= n;i++)cin >> a[i];
for (int i = 1;i <= n;i++)pre[i] = pre[i - 1] + a[i];
for (int i = 1;i <= n;i++)f1[i][0] = pre[i], f2[i][0] = f1[i][0];
for (int j = 1;j <= 30;j++) {
for (int i = 0;i + (1 << j) - 1 <= n;i++) { // After changing i=1 to i=0, it passed?
f1[i][j] = max(f1[i][j - 1], f1[i + (1 << (j - 1))][j - 1]);
f2[i][j] = min(f2[i][j - 1], f2[i + (1 << (j - 1))][j - 1]);
}
}
int q;cin >> q;
while (q--) {
int l, r;cin >> l >> r;l--;
int k = __lg(r - l + 1);
cout << max(f1[l][k], f1[r - (1 << k) + 1][k]) - min(f2[l][k], f2[r - (1 << k) + 1][k]) << '\n';
}
}cppIf this problem were modified slightly: removing the absolute value, it becomes 245. Can You Answer These Questions? - AcWing ↗
Nowcoder Weekly Contest 31 - E Little Red’s Subset Negation#
Little Red has an array. She plans to select several elements and multiply them by -1 so that the sum of all elements is 0. Little Red wants to know the minimum number of elements she needs to select.
Solution.#
DP
#define N 40000
int i, j, k, n, m, t, res = -1;
bitset<80005> f[205];
int main() {
ios::sync_with_stdio(0);
f[0][N] = 1;
cin >> n;
for (i = 1;i <= n;i++) {
cin >> k;
for (j = n;j >= 0;j--) {
if (k >= 0) {
f[j] >>= k;
if (j) f[j] |= (f[j - 1] << k);
} else {
f[j] <<= -k;
if (j) f[j] |= (f[j - 1] >> -k);
}
}
}
for (i = 0;i <= n;i++)
if (f[i][N]) {
res = i; break;
}
cout << res;
}cppIf ndp does not store the value of , set it to y. If it already exists, update it to min (ndp[c + x], y).
The same method is used for , setting it to y + 1 or updating it to min (ndp[c - x], y + 1).
For each piece of input data, it must be added to or subtracted from the numbers in the array.
dp[i][j] = min (dp[i - 1][j + arr[i]], dp[i - 1][j - arr[j]] + 1)
int main() {
map<int, int> dp;
int n;
cin >> n;
dp[0] = 0;
for (int i = 1; i <= n; i++) {
int x;
cin >> x;
map<int, int> ndp;
for (auto [c, y] : dp) {
if (!ndp.count(c + x)) ndp[c + x] = y;
else ndp[c + x] = min(ndp[c + x], y);
if (!ndp.count(c - x)) ndp[c - x] = y + 1;
else ndp[c - x] = min(ndp[c - x], y + 1);
}
dp = ndp;
}
if (!dp.count(0)) cout << -1;
else cout << dp[0];
}cppx + y = s
x - y = 0
Select the minimum number of elements from the set to exactly sum to . When implemented, it’s a 0/1 knapsack problem of “minimum number of items to pick to achieve a specific sum”: the state records the minimum number of picks to reach a certain sum, and finally check if we can transition to .
Nowcoder Weekly Contest 52 - C Little Red’s Number Pair Elimination#
Little Red has an array of length , where the value at the -th position is . She wants to reduce the length of the array as much as possible in the following ways.
- When and there exists a pair satisfying and , then and can be eliminated.
- When and there exists a pair satisfying and , then and can be eliminated.
Please output the minimized length of the array.
Classify based on being +/-/0.
From the given conditions:
:
:
In summary: Only when do the conditions for elimination not hold.
Greedy idea: Positive numbers are not conducive to calculating the answer, so try to eliminate positive numbers first, i.e., first eliminate pairs where .
#define int long long
void solve() {
int n;cin >> n;
int pos = 0, neg = 0, z = 0;
map<int, int>mp;
for (int i = 1;i <= n;i++) {
int x;cin >> x;
if (x == 0) {
z++;
} else if (x > 0) {
pos++;mp[x]++;
if (mp[x] == 2) {
pos -= 2, mp[x] = 0;
}
} else {
neg++;
}
}
if (pos <= neg) {
cout << (neg - pos + z) % 2 << '\n';
} else {
cout << pos - neg + z << '\n';
}
}cppNowcoder Weekly Contest 52 - E Little Red Adding Edges to the Graph#
Little Red has an undirected graph with nodes and edges. The weight of each node is .
Little Red now wants to add edges to connect the graph. The cost of each connection is the maximum element value of the newly formed connected block. Little Red wants to know the minimum total cost required to make the graph connected.
This problem turned out to be the simplest…
Following the idea of condensation, the weight of each block is .
Then it’s easy to see that the answer is .
#define int long long
void solve() {
int n, m;cin >> n >> m;
vector<int> a(n + 1);
for (int i = 1;i <= n;i++)cin >> a[i];
vector<vector<int>> g(n + 1);
for (int i = 1;i <= m;i++) {
int u, v;cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
vector<int> vis(n + 1);
int sum = 0, mi = 1e18;
for (int i = 1;i <= n;i++) {
if (!vis[i]) {
int mx = a[i];
queue<int>q;vis[i] = 1;q.push(i);
while (q.size()) {
int u = q.front();q.pop();
for (auto v : g[u]) {
if (vis[v])continue;
vis[v] = 1;
mx = max(mx, a[v]);
q.push(v);
}
}
mi = min(mi, mx);
sum += mx;
}
}
cout << sum - mi << '\n';
}cppNowcoder Weekly Contest 52 - F Little Red’s Bracket String#
Little Red has a string containing only ’(’ , ’)’ and ’?’. Little Red wants to know how many ways there are to replace ’?’ with ’(’ or ’)’ such that there exists a cyclic shift making the string a valid bracket sequence.
Assume a cyclic shift of a string of length is . Then, if string is a valid bracket sequence, is also a valid bracket sequence.
Solution#
Refer to the solution by Little Brother Xue: Problem Solution | Little Red’s Bracket String_Nowcoder Blog ↗ -> Concrete Mathematics P301
New knowledge: Raney’s Lemma: If , then among all its cyclic shifts, exactly one satisfies that all prefix sums are positive.
This tells us that as long as the sequence sum is 0, it is valid.
constexpr int mod = 1e9 + 7;
void solve() {
int n;cin >> n;
string s;cin >> s;
if (n & 1) {
cout << "0\n";return;
}
int x = 0, y = 0;
for (auto c : s) {
if (c == '(') x++;
else if (c == ')') y++;
}
cout << C(n - x - y, n / 2 - x) << '\n';
}cppNowcoder Weekly Contest 47 - D Cute Numbers#
Mengmeng likes “cute numbers”, which need to satisfy the following two conditions:
- The number modulo is not .
- The last digit of the number is not .
Please tell him what the -th cute number is.
If we know a value , we can calculate how many numbers before are excluded.
The number of excluded numbers:
Then it satisfies:
Directly enumerating the answer will definitely time out, but since the answer is monotonic (the larger the number, the larger the answer), binary search can be used.
#define int long long
void solve() {
int n;cin >> n;
int l = 1, r = 1e14;
while (l < r) {
int mid = l + r >> 1;
int x = mid - mid / 3 - (mid - 3) / 10 + (mid - 3) / 30;
if (x >= n) {
r = mid;
} else {
l = mid + 1;
}
}
cout << l << "\n";
}cppNowcoder Weekly Contest 47 - E Qianqian’s Calculator#
Qianqian has a calculator that displays all leading zeros when showing numbers.
On this calculator, 0-9 are displayed as:
That is, when the calculator display has 10 digits, displaying the number 123456 would show as “0000123456”.
Qianqian noticed that sometimes the number displayed on the calculator is an axially symmetric figure, such as “80808”
(“80808” can have a horizontal axis of symmetry, or a vertical axis of symmetry. And some numbers might be symmetric only about the horizontal or only about the vertical axis, but such numbers are still considered axially symmetric.)
Question: If the calculator displays numbers with digits, how many different axially symmetric figures can it display?
Solution#
Since , it’s usually solved in .
Inclusion-Exclusion: Horizontal Symmetry + Vertical Symmetry − (Horizontal and Vertical Symmetry)
Horizontal Symmetry: can be arbitrarily combined (they are horizontally symmetric), i.e., .
Vertical Symmetry: There are four possibilities: . They can only be placed with central symmetry.
Note: cannot be placed; in the calculator display, it is right-aligned and not symmetric.
If is odd, the middle position can only be or , so the answer is . If even, it is . Simplified, odd and even can be combined into .
Need to subtract the double-counted part that is both horizontally and vertically symmetric. Only are double-counted when placed arbitrarily. This part is .
The answer is , solved in .
void solve() {
int n;cin >> n;
cout << (qpow(4, n) + qpow(2, n) + mod - qpow(2, (n + 1) / 2)) % mod;
}cppNowcoder Weekly Contest 47 - F Huahua’s Map#
The map of City A is an grid. The character ’#’ represents an obstacle, and ’.’ represents open space. Huahua lives at the top-left corner , and Huahua’s friend Mengmeng lives at the bottom-right corner . Huahua wants to go to Mengmeng’s house.
If Huahua walks on open space, there is no cost. But if he wants to walk on an obstacle point, he needs to destroy that obstacle first. He can move in four adjacent directions each time, i.e., from to , , , .
Huahua can spend a cost of to destroy all obstacles in the -th column.
Please calculate the minimum cost for Huahua to go to Mengmeng’s house.
Data range:
Solution#
Digit DP / Shortest Path (dijkstra)
Shortest path approach: Each time you need to go to a place containing #, the cost for that column is the same. Add all points in that column and their costs to the graph.
Method 1:#
{c++}dp[i][j] is the minimum cost to reach point . The answer is {c++}dp[n - 1][m - 1].
Time complexity: . Will time out if .
A max heap can also be used, just add a sign when inserting.
void solve() {
int n, m; cin >> n >> m;
vector<string> g(n);
for (int i = 0; i < n; i++) cin >> g[i];
vector<int> cost(m);
for (int i = 0; i < m; i++) cin >> cost[i];
vector<vector<int>> dp(n, vector<int>(m, INT_MAX));
priority_queue<tuple<int, int, int>, vector<tuple<int, int, int>>, greater<tuple<int, int, int>>> pq;
if (g[0][0] == '.') {
pq.push({0,0,0});
dp[0][0] = 0;
} else {
for (int i = 0; i < n; i++) {
pq.push({cost[0], i,0});
dp[i][0] = cost[0];
}
}
while (!pq.empty()) {
auto [c, x, y] = pq.top();pq.pop();
if (c > dp[x][y]) continue;
const int dx[] = {0, 0, 1, -1}, dy[] = {1, -1, 0, 0};
for (int i = 0;i < 4;i++) {
int cx = x + dx[i], cy = y + dy[i];
if (cx < 0 || cx >= n || cy < 0 || cy >= m) continue;
if (g[cx][cy] == '.') {
if (dp[cx][cy] > c) {
dp[cx][cy] = c;
pq.push({dp[cx][cy], cx, cy});
}
} else {
for (int j = 0; j < n; j++) {
if (dp[j][cy] > c + cost[cy]) {
dp[j][cy] = c + cost[cy];
pq.push({dp[j][cy], j, cy});
}
}
}
}
}
cout << dp[n - 1][m - 1] << '\n';
}cppMethod 2:#
See: Nowcoder Weekly Contest Round 47 Problem Solving Report | Ke Scholar _Nowcoder Blog ↗
Time complexity is . It also passes when .
void solve() {
int n, m;
cin >> n >> m;
vector<string> g(n);
for (auto& s : g) cin >> s;
vector<int> cost(m);
for (auto& x : cost) cin >> x;
vector<vector<int>> dp(n + 1, vector<int>(m, INT_MAX));
priority_queue<tuple<int, int, int>, vector<tuple<int, int, int>>, greater<tuple<int, int, int>>> pq;
if (g[0][0] == '.') {
pq.emplace(0, 0, 0);
dp[0][0] = 0;
} else {
pq.emplace(cost[0], n, 0);
dp[n][0] = cost[0];
}
while (!pq.empty()) {
auto [c, y, x] = pq.top();
pq.pop();
if (c > dp[y][x]) {
continue;
}
if (y == n) {
for (int i = 0; i < n; i++) {
if (dp[i][x] > c) {
dp[i][x] = c;
pq.emplace(dp[i][x], i, x);
}
}
} else {
vector<pair<int, int>> dir = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
for (auto& [dy, dx] : dir) {
int ty = y + dy, tx = x + dx;
if (0 <= ty && ty < n && 0 <= tx && tx < m) {
if (g[ty][tx] == '.' && dp[ty][tx] > c) {
dp[ty][tx] = c;
pq.emplace(dp[ty][tx], ty, tx);
}
}
}
for (int dx = -1; dx <= 1; dx++) {
int tx = x + dx;
if (0 <= tx && tx < m) {
if (dp[n][tx] > c + cost[tx]) {
dp[n][tx] = c + cost[tx];
pq.emplace(dp[n][tx], n, tx);
}
}
}
}
}
cout << dp[n - 1][m - 1] << endl;
}cppNowcoder Weekly Contest 35 - F/G Little Red’s Subsequence Weight Sum#
Little Red defines the weight of an array as: the number of factors of the product of all elements in the array. For example, the weight of is 4.
Now Little Red has an array. She wants to find the sum of the weights of all non-empty subsequences of the array. Can you help her? Since the answer may be too large, output it modulo .
Define a subsequence of an array as: selecting several elements from left to right (not necessarily consecutively) to form an array. For example, subsequences of include , etc. Therefore, an array of size has exactly subsequences.
Solution#
Yang Hui’s Triangle for Combinations / Inverse Elements / Number Theory
Let be the counts of respectively, then:
void solve() {
int n;cin >> n;
vector<vector<ll>> c(n + 1, vector<ll>(n + 1));
for (int i = 0;i <= n;i++) {
for (int j = 0;j <= i;j++) {
if (j == 0 || j == i)c[i][j] = 1;
else c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
}
}
array<int, 4> num = {};
ll t = 1;
for (int i = 1;i <= n;i++) {
int x;cin >> x;
num[x]++;
}
ll ans = 0;
for (int i = 1;i <= num[1];i++) {
t = (2 * t) % mod;
}
for (int i = 0;i <= num[2];i++) {
for (int j = 0;j <= num[3];j++) {
ans += c[num[2]][i] * c[num[3]][j] % mod * (i + 1) % mod * (j + 1) % mod * t % mod;
ans %= mod;
}
}
cout << (ans + mod - 1) % mod << '\n';
}cppconst int mod = 1e9 + 7;
vector<ll> fact(1e5 + 1);
ll c(int n, int m) {
return fact[n] * (qpow(fact[n - m], mod - 2)) % mod * (qpow(fact[m], mod - 2)) % mod;
}
void solve() {
int n;cin >> n;
fact[0] = 1;
for (int i = 1;i <= n;i++)fact[i] = fact[i - 1] * i % mod;
array<int, 4> num = {};
for (int i = 0;i < n;i++) {
int x;cin >> x;num[x]++;
}
ll t = qpow(2, num[1]);
ll ans = 0, c2 = 0, c3 = 0;
for (int i = 0;i <= num[2];i++) {
c2 += c(num[2], i) * (i + 1) % mod;
c2 %= mod;
}
for (int i = 0;i <= num[3];i++) {
c3 += c(num[3], i) * (i + 1) % mod;
c3 %= mod;
}
cout << (c2 % mod * c3 % mod * t % mod - 1 + mod) % mod << '\n';
}cppNowcoder Weekly Contest 55 - E Little Red’s Sequence Product 2.0#
For an integer sequence of length , define , i.e., the product of the first terms. The weight of this sequence is the number of digits among whose units digit is .
Little Red has an integer sequence of length . She wants to know the sum of the weights of all non-empty subsequences of this sequence.
Solution#
DP
represents the number of schemes among the first numbers that end with .
Let be the current state, and be the previous state, then:
The current state must include the previous state, i.e.,
The current number is , then means that after adding the current number, it ends with . Therefore:
When adding the current number, if it ends with 6, the requirement is met. Suppose this subsequence is . Then all sequences with larger indices can include this subsequence. There are of them, and each can be chosen or not, giving ways.
#define int long long
constexpr int mod = 1e9 + 7;
void solve() {
int n;cin >> n;
vector<int> a(n + 1);
for (int i = 1;i <= n;i++) {
cin >> a[i];a[i] %= 10;
}
vector<array<int, 10>> f(n + 1); // Represents the number of schemes among the first i numbers ending with j
f[0][1] = 1;
int ans = 0;
for (int i = 1;i <= n;i++) {
for (int j = 0;j < 10;j++) {
if (j * a[i] % 10 == 6) {
ans += f[i - 1][j] * qpow(2, n - i) % mod;ans %= mod;
}
f[i][j] += f[i - 1][j];f[i][j] %= mod;
f[i][j * a[i] % 10] += f[i - 1][j];f[i][j * a[i] % 10] %= mod;
}
}
cout << ans << '\n';
}cppF’s computational geometry hints that I should start learning computational geometry!