FXJ Wiki

Back

Nowcoder Solutions: Winter Contests, Weeklies, and Multi-School

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.
views | comments

Scope of Inclusion#

  • Winter Break 2 - I/J
  • Winter Break 2 - D
  • Winter Break 3 - L/M
  • Winter Break 3 - G/H
  • Winter Break 5 - G/H
  • Nowcoder Multi-University Training 4 - H
  • Nowcoder Multi-University Training 4 - C
  • Nowcoder Weekly Contest 60 - D
  • Nowcoder Weekly Contest 60 - E
  • Nowcoder Weekly Contest 60 - F
  • Nowcoder Weekly Contest 51 - D
  • Nowcoder Weekly Contest 51 - E
  • Nowcoder Weekly Contest 51 - F
  • Nowcoder Weekly Contest 31 - E
  • Nowcoder Weekly Contest 52 - C
  • Nowcoder Weekly Contest 52 - E
  • Nowcoder Weekly Contest 52 - F
  • Nowcoder Weekly Contest 47 - D
  • Nowcoder Weekly Contest 47 - E
  • Nowcoder Weekly Contest 47 - F
  • Nowcoder Weekly Contest 35 - F/G
  • Nowcoder 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 aia_i.

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:

if(u=v)wu,v=0,otherwise,wu,v=au+av±auavif(u=v) w_{u,v}=0, otherwise, w_{u,v}=\mid a_{u}+a_{v}\mid\pm\mid a_{u}-a_{v}\mid

Define dist(i,jdist (i, j) as the shortest path distance from vertex ii to vertex jj. Find i=1nj=1ndist(i,j)\sum\limits_{i=1}^ n\sum\limits_{j=1}^ ndist(i,j)

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 wi,j+=2×a[u]w_{i,j}+=2\times a[u]. Otherwise, wi,j+=2×a[v]w_{i,j}+=2\times a[v].

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 *= 2
python
  • 1,2,3,4,,n1pre[n1]pre[0]1,2,3,4,\dots,n-1\to pre[n-1]-pre[0]
  • 2,3,4,,n1pre[n1]pre[1]2,3,4,\dots,n-1\to pre[n-1]-pre[1]
  • 3,4,,n1pre[n1]pre[2]3,4,\dots,n-1\to pre[n-1]-pre[2]
  • n1pre[n1]pre[n2]n-1\to pre[n-1]-pre[n-2]
cnt = pre[n - 1]
for i (0, n - 2)
    ans += cnt - pre[i]
python
for(int i = 2, j = 1; i <= n; i ++, j ++)
    ans += w[i] * 2 * j;
cpp
void 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';
}
cpp

J (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';
cpp

Correct 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';
}
cpp

2024 Nowcoder Winter Break Algorithm Basic Training Camp 2 - D Tokitsukaze and Slash Draw#

Tokitsukaze’s deck has n(1n5000)n(1\leq n\leq 5000) cards. She already knows that the card “One Shot Kill! Iai Draw” is the kk-th card from the bottom of the deck. She selects m(1m1000)m(1\leq m\leq 1000) types of cards that can adjust the order of the cards in the deck. The effect of the ii-th type of card is: take the top aia_i 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 aia_i times. To activate the effect of the ii-th type of card, you need to pay a cost\text{cost} of bib_i.

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 cost\text{cost} required. If not, output -1.

Solution#

DP | dijkstra (Congruence Shortest Path Model)

dp[x]=min(dp[x],dp[(x+ai)%n]+bi)dp[x]=\min(dp[x],dp[(x+a_{i})\%n]+b_{i})

D_Bilibili_bilibili

mnimn_{i} represents, under the condition of mod n, the minimum cost\text{cost} to move the target card up by ii steps.

(Didn’t quite understand \dots)

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

【Continuously Updated】2024 Nowcoder Winter Break Algorithm Basic Training Camp 2 Problem Solutions | JorbanS - Zhihu

 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

D_Bilibili_bilibili

dp[x]=min(dp[x],dp[(x+ai)%n]+bi)dp[x]=\min(dp[x],dp[(x+a_{i})\%n]+b_{i})

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';
}
cpp

2024 Nowcoder Winter Break Algorithm Basic Training Camp 3 - L/M Zhinai’s 36 Multiples (easy)(normal)#

Define the operation ff as concatenating two positive integers literally from left to right.

Zhinai now has a positive integer array aa of size NN, with the ii-th element being aia_i. He wants to select two positive integers and concatenate them (front to back) so that the concatenated number is a multiple of 3636. How many feasible schemes does Zhinai have?

She wants to know how many ordered pairs (i,j)(ij)(i, j)(i≠j) satisfy that f(ai,aj)f (a_i, a_j) is a multiple of 3636.

  • easy: 1N1000,1ai101\leq N\leq 1000,1\leq a_{i}\leq 10
  • normal: 1N105,1ai10181\leq N\leq 10^5,1\leq a_{i}\leq 10^{18}

easy:\text{easy:}#

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';
}
cpp

Method 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

normal:\text{normal:}#

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, (a+b)%36=(a%36+b%36)%36(a+b)\%36=(a\%36+b\%36)\%36.

So we can directly use buckets to count the remainder of each number modulo 36. Also, 36 has a special property: 10k %36=28(k2)10^k\ \%36=28(k\geq 2), so we only need to know if it’s a 10-digit number.

f(j,i)=j×10k+if(j,i)=j\times10^k+i (where kk is the number of digits in ii)

If k2(i10),j×10k%36=j×28k\geq 2(i\geq 10), j\times10^k\%36=j\times28
If k=1(i<10),j×10k%36=j×10k=1(i<10), j\times10^k\%36=j\times10

f(j,i)f(j,i) is (j * (i < 10LL ? 10LL : 28LL) + i). Here, jj is the result of a[i] mod 36\text{mod 36}, ii is a[i], and sum[i]sum[i] represents the count of numbers where a[i]%36a[i]\%36 yields the same result (proving that these numbers differ by multiples of 36, which does not affect the result; they cancel out in f(j,i)%36f(j,i)\%36, allowing them to be added together to reduce complexity).

For each element in a[i], iterate through f(j,a[i])f(j, a[i]). 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';
}
cpp

I didn’t quite understand the code. My main idea was to preprocess the sum[i]sum[i] 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';
}
cpp

2024 Nowcoder Winter Break Algorithm Basic Training Camp 3 - G/H Zhinai’s Comparison Function (easy)(normal)#

cmp(x,y)cmp(x,y):

  • x<y,cmp(x,y)=1x<y, cmp (x, y)=1
  • xy,cmp(x,y)=0x\geq y, cmp(x,y)=0

There are integer variables a1,a2,a3a_{1}, a_{2}, a_{3}. Given NN sets of cmp(ax,ay)cmp(a_{x}, a_{y}) values, determine if there is a contradiction.

  • easy: 1N21\leq N\leq 2
  • normal: 1N501\leq N\leq 50

easy:\text{easy:}#

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

normal:\text{normal:}#

Enumerate a1,a2,a3(1,2,3)a_{1}, a_{2}, a_{3} (1, 2, 3). If there exists a case where z=1&&a[x]a[y]z=0&&a[x]<a[y]z=1 \&\& a[x] \geq a[y] \mid \mid z=0 \&\& a[x] < a[y], 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();
}
cpp

2024 Nowcoder Winter Break Algorithm Basic Training Camp 5 - G/H sakiko’s Permutation Construction#

sakiko wants to construct a permutation pp of length nn, such that for every pi+i(1in)(1n106)p_i+i (1≤i≤n)(1\leq n\leq 10^6) is a prime number.

Solution#

Network Flow / Pattern Finding

Found: If n=4:n=4: p:4,3,2,1p:4,3,2,1, then pi+ip_{i}+i is 5,5,5,55,5,5,5, each term being n+1n+1

For nn, if isPrime(n+1)\text{isPrime(n+1)}, then p:{n,n1,,2,1}p:\{n,n-1,\dots,2,1\} pi+i:{n+1(n)}p_{i}+i:\{n+1(n)\}

For nn, if isPrime(n+2)\text{isPrime(n+2)}, then p:{1,n,n1,,3,2}p:\{1,n,n-1,\dots,3,2\} pi+i:{2,n+2(n1)}p_{i}+i:\{2,n+2(n-1)\}

Found: If n=8:n=8: 113=811-3=8 p:{2,1,8,7,6,5,4,3}p:\{2,1,8,7,6,5,4,3\} pi+i={3,3,11(6)}p_{i}+i=\{3,3,11(6)\}

If n=7:11(51)=7 p:{1,3,2,7,6,5,4}n=7:11-(5-1)=7 \ p:\{1,3,2,7,6,5,4\} pi+i:{2,5,5,11(4)}p_{i}+i:\{2,5,5,11(4)\}

For even n:n: (n+m)(m)=n(n+m)-(m)=n If we can ensure that (n+m)(m)(n+m)(m) are both prime, then we can construct p:{m1,m2,1,n,n1,,m}p:\{m-1,m-2,\dots 1,n,n-1,\dots,m\} pi+i:{m(m1),(n+m)(nm+1)}p_{i}+i:\{m(m-1),(n+m)(n-m+1)\}

For odd n:n: (n+m)(m1)=n(n+m)-(m-1)=n If we can ensure that (n+m)(m)(n+m)(m) are both prime, then we can construct p:{1,m2,m3,,2,n,n1,nm+1}p:\{1,m-2,m-3,\dots,2,n,n-1,\dots n-m+1\} pi+i:{2,(m)(m2),(n+m)(nm+1)}p_{i}+i:\{2,(m)(m-2),(n+m)(n-m+1)\}

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];
}
cpp

2024 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 a\textstyle a of length n\textstyle n, you can perform the following operations any number of times (possibly zero):

Select an index p\textstyle p, and then perform one of the following two operations:

  1. For all i\textstyle i such that aiap\textstyle a_i \leq a_p, let aiai+2(apai)\textstyle a_i \gets a_i + 2(a_p - a_i).
  2. For all i\textstyle i such that aiap\textstyle a_i \geq a_p, let aiai2(aiap)\textstyle a_i \gets a_i - 2(a_i - a_p).

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';
}
cpp

2024 Nowcoder Multi-University Training 4 - C Sort 4#

Given a permutation \textstyle ^\dagger of length n\textstyle n. 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';
}
cpp

Nowcoder Weekly Contest 60 - D We Are So Awesome#

Today, nn children are gathered together bragging. Each of them has a certain number of little stars in their hands. For convenience, we represent them as a1,a2,,ana_1, a_2, \dots, a_n.
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 nn!”
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: O(n2w)1.5e8O\left( \frac{n^2}{w} \right)\approx1.5e8 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";
}
cpp

If we can already form any number in [1,x][1,x], what condition must the next number aia_{i} satisfy to be able to form any number in [1,x+ai][1,x+a_i]?

Condition: aix+1a_{i}\leq x+1. When ai>x+1a_{i}> x+1, the number x+1x+1 cannot be formed. Otherwise, aia_{i} can definitely form the numbers in the interval [x+1,x+ai][x+1,x+a_{i}] 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";
}
cpp

Nowcoder 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 nn points on the track. The teacher placed two poles at points 11 and nn, called the left pole and the right pole, as the turning points for the shuttle run.
\,\,\,\,\,\,\,\,\,The teacher stipulated that a total of mm 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 m1m-1 turns need to be made. Zaoly\sf Zaoly suddenly discovered that the poles are movable, so he had a bold idea —
\,\,\,\,\,\,\,\,\,\,\,\,\,\,\bullet\, 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 00), 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);
\,\,\,\,\,\,\,\,\,\,\,\,\,\,\bullet\, 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 00), 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 nn and mm, how many different pushing methods does Zaoly\sf Zaoly have? Since the answer may be very large, please output the answer modulo (109+7)(10^9+7). 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 m1m-1 turns, each time you must push at least 1, and the total cannot exceed n2n-2, i.e., [m1,n2]\in[m-1,n-2].

1931 (925div3): Review of Combinatorics

Equivalent to having x(m1xn2)x(m-1\leq x\leq n-2) balls placed into m1m-1 boxes (each box must have at least one ball). That is, C(x1,m2)C(x-1,m-2)

So the answer is C(n3,m2)+C(n2,m2)++C(m2,m2)=i=m1n2C(i1,m2)\displaystyle C(n-3,m-2)+C(n-2,m-2)+\dots+C(m-2,m-2)=\sum_{i=m-1}^{n-2}C(i-1,m-2)

The time complexity is O(Tnlogn)O(Tn\log n), which is too high. So we need another way to solve it.

Introduce ama_{m}, representing how many “balls” are not used. So we have:

x1+x2++xm1+xm=n2,xi1xm0x_{1}+x_{2}+\dots+x_{m-1}+x_{m}=n-2, x_{i}\geq 1\cap x_{m}\geq 0

So:

(x11)+(x21)++(xm11)+xm=n2,xi0(x_{1}-1)+(x_{2}-1)+\dots+(x_{m-1}-1)+x_{m}=n-2, x_{i}\geq 0

    x1+x2++xm=n2m+1,xi0\implies x_{1}+x_{2}+\dots+x_{m}=n-2-m+1, x_{i}\geq 0

That is, there are nm1n-m-1 balls to be placed into mm boxes (boxes can be empty). How many ways?

C(n2m1+m1,m1)=C(n2,m1)\to C(n-2-m-1 +m-1,m-1)=C(n-2,m-1)

    C(n2,m1)\implies C(n-2,m-1)

Time complexity O(Tlogn)O(T\log n)

Proof thati=m1n2C(i1,m2)=C(n2,m1)\displaystyle \sum_{i=m-1}^{n-2}C(i-1,m-2)=C(n-2,m-1) holds

Considering the properties of combinatorial numbers, we know:

(ij)=(i1j)+(i1j1)\binom{i}{j} = \binom{i-1}{j} + \binom{i-1}{j-1}

Using this property, treating the original equation as an accumulation, it is equivalent to:

i=m1n2(i1m2)=i=m1n2(i1im+1)\sum_{i=m-1}^{n-2} \binom{i-1}{m-2} = \sum_{i=m-1}^{n-2} \binom{i-1}{i-m+1}

Thus, this sum can be recombined and gradually simplified using Pascal’s identity to:

i=m1n2(i1m2)=(n2m1)\sum_{i=m-1}^{n-2} \binom{i-1}{m-2} = \binom{n-2}{m-1}

This is a given combinatorial property. From a combinatorial perspective, the combinatorial number on the right, (n2m1)\binom{n-2}{m-1}, represents the number of ways to choose m1m-1 elements from n2n-2 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';
}
cpp

Nowcoder Weekly Contest 60 - F Stuttering#

Zaoly\sf Zaoly wants to say a sentence. This sentence has nn words. He wants to say them one by one. Unfortunately, Zaoly\sf Zaoly stutters:
When saying the 11st word, the probability that the next word to say advances to the 22nd word is a1a1+b1\frac {a_1} {a_1 + b_1}, and the probability that it remains the 11st word is b1a1+b1\frac {b_1} {a_1 + b_1}.
When saying the iith (2in12 \leq i \leq {n - 1}) word, the probability that the next word to say advances to the i+1i + 1st word is ai2ai2+2aibi+bi2\frac {a_i^2} {a_i^2 + 2 a_i \cdot b_i + b_i^2}, the probability that it remains the iith word is 2aibiai2+2aibi+bi2\frac {2 a_i \cdot b_i} {a_i^2 + 2 a_i \cdot b_i + b_i^2}, and the probability that it retreats to the i1i - 1st word is bi2ai2+2aibi+bi2\frac {b_i^2} {a_i^2 + 2 a_i \cdot b_i + b_i^2}.

When saying the nnth word, the speech ends and stops.

Until the speech ends, what is the expected total number of words Zaoly\sf Zaoly says?

Solution#

Let eu,u+1e_{u,u+1} represent the expected number of steps to go from uu+1u\to u+1. According to the problem statement: (let the three probabilities be p1i,2i,3ip_{1i,2i,3i})

eu,u+1=p1u×eu+1,u+1+p2u×eu,u+1+p3u×eu1,u+1+1e_{u,u+1}=p_{1u}\times e_{u+1,u+1}+p_{2u}\times e_{u,u+1}+p_{3u}\times e_{u-1,u+1}+1

We have eu1,u+1=eu1,u+eu,u+1e_{u-1,u+1}=e_{u-1,u}+e_{u,u+1}. Substituting gives: (eu,u=0e_{u,u}=0)

    eu,u+1=1+p3u×eu1,up1ubi2×ei1,i+(ai+bi)2ai2\displaystyle \implies e_{u,u+1}=\frac{1+p_{3u}\times e_{u-1,u}}{p_{1u}}\to\frac{b_{i}^2\times e_{i-1,i}+(a_{i}+b_{i})^2}{a_{i}^2}

Let ei,i+1eie_{i,i+1}\to e_{i} represent the expected number of steps to go from ii+1i\to i+1.

e0=1,e1=a1+b1a1e_{0}=1, e_{1}= \frac{a_{1}+b_{1}}{a_{1}}

ei=bi2×ei1+(ai+bi)2ai2\displaystyle e_{i}=\frac{b_{i}^2\times e_{i-1}+(a_{i}+b_{i})^2}{a_{i}^2}

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';
}
cpp

Official 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';
}
cpp

Nowcoder Weekly Contest 51 - D Little Red’s gcd#

Given two positive integers a,ba, b, output their greatest common divisor gcd(a,b)\gcd(a, b).

1a101061\leq a \leq 10^{10^6}.
1b1091\leq b \leq 10^9.

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) x[0,b)x\in[0,b)

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: (a×b)%p=(a%p×b%p)%p(a\times b)\%p=(a\%p\times b\%p)\%p

From this property, a can be divided into several blocks, assuming each split is 9 digits     a0×109×a1×1018×\implies a_{0}\times10^9\times a_{1}\times10^{18}\times \dots (but this seems unnecessary…)

Just calculate digit by digit.

Then amodb=aimodba \bmod b=\sum a_{i}\bmod b

#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

    \implies ans=(a[0]×10n1modb+a[1]×10n2modb+...+a[i]×10ni1modb)ans = (a[0]\times 10^{n-1} \mod b + a[1]\times 10^{n-2} \mod b + ... + a[i]\times 10^{n-i-1} \mod b)

#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';
}
cpp

Nowcoder Weekly Contest 51 - E Little Red Walking Through Matrix#

Given an n×nn \times n matrix, each element in the matrix is a positive integer. Little Red is currently at the top-left corner (1,1)(1,1). Each time, she can move from (x,y)(x, y) to (x+1,y)(x+1, y), (x,y+1)(x, y+1), (x1,y)(x-1, y), or (x,y1)(x, y-1), but cannot move outside the matrix. Little Red hopes to find a path to the bottom-right corner (n,n)(n,n). 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 O(n2logn)O(n^2\log n). 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';
}
cpp

Union-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 nn numbers aia_i.
Little Red has qq queries. For each query, given an interval [l,r][l,r], find the maximum absolute value of the sum of a contiguous subarray within the interval. That is, find x,yx,y such that lxyrl \leq x \leq y \leq r, maximizing abs(a[x]+a[x+1]+.....+a[y])\mathrm{abs}(a[x]+a[x+1]+.....+a[y]).

Solution#

Segment Tree / Mo’s Algorithm / Sparse Table

Information needed for the segment tree:

  1. 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).
  2. Maximum and minimum values

The problem actually hints: abs(a[x]+a[x+1]+.....+a[y])\mathrm{abs}(a[x]+a[x+1]+.....+a[y]) is a contiguous segment, i.e., pre[y]pre[x1]pre[y]-pre[x-1]. The maximum value minus the minimum value of prefix sums within the interval [l,r][l,r] 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';
    }
}
cpp

If 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;
}
cpp

If ndp does not store the value of c+xc + x, set it to y. If it already exists, update it to min (ndp[c + x], y).

The same method is used for cxc - x, 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];
}
cpp

x + y = s
x - y = 0 y=s2\to y=\frac{s}{2}
Select the minimum number of elements from the set to exactly sum to S/2S/2. 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 S/2S/2.

Nowcoder Weekly Contest 52 - C Little Red’s Number Pair Elimination#

Little Red has an array aa of length nn, where the value at the ii-th position is aia_i. She wants to reduce the length of the array as much as possible in the following ways.

  • When len(a)>1len(a)>1 and there exists a pair (i,j)(i,j) satisfying i<ji<j and ai+aj0a_i + a_j \leq 0, then aia_i and aja_j can be eliminated.
  • When len(a)>1len(a)>1 and there exists a pair (i,j)(i,j) satisfying i<ji<j and aiaj0a_i \oplus a_j \leq 0, then aia_i and aja_j can be eliminated.

Please output the minimized length of the array.

Classify based on aia_{i} being +/-/0.

From the given conditions:

ai+aj0a_{i}+a_{j}\leq 0:
    \implies

  • (0,0)(\leq0,\leq0)
  • (>0,<0)(>0,<0)

aiaj0a_{i}\oplus a_{j}\leq 0:
    \implies

  • ai=aja_i=a_{j}
  • (0,<0)(\geq0,<0)

In summary: Only when ai0aj0aiaja_{i}\geq 0\cap a_{j}\geq 0\cap a_{i}\neq a_{j} 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 ai=aj>0a_{i}=a_{j}>0.

#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';
    }
}
cpp

Nowcoder Weekly Contest 52 - E Little Red Adding Edges to the Graph#

Little Red has an undirected graph with nn nodes and mm edges. The weight of each node is aia_i.
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 wj=max(ai),aiBlockw_{j}=\max(a_{i}), a_{i}\in Block.

Then it’s easy to see that the answer is wimin(wi)\sum w_{i}-\min(w_{i}).

#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';
}
cpp

Nowcoder 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 ss of length nn is s[k:n]+s[1:k)s[k:n] + s[1:k). Then, if string ss is a valid bracket sequence, s[k:n]+s[1:k)s[k:n] + s[1:k) 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 i=1mxi=1\displaystyle \sum\limits_{i=1}^mx_{i}=1, 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';
}
cpp

Nowcoder Weekly Contest 47 - D Cute Numbers#

Mengmeng likes “cute numbers”, which need to satisfy the following two conditions:

  1. The number modulo 33 is not 00.
  2. The last digit of the number is not 33.
    Please tell him what the nn-th cute number is.

If we know a value xx, we can calculate how many numbers before xx are excluded.

The number of excluded numbers: x3+x310x330\lfloor{\frac{x}{3}}\rfloor+\lfloor{\frac{x-3}{10}}\rfloor-\lfloor{\frac{x-3}{30}}\rfloor

Then it satisfies: n+x3+x310x330=xn+\lfloor{\frac{x}{3}}\rfloor+\lfloor{\frac{x-3}{10}}\rfloor-\lfloor{\frac{x-3}{30}}\rfloor=x

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";
}
cpp

Nowcoder 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 n(1n109)n(1\leq n\leq 10^9) digits, how many different axially symmetric figures can it display?

Solution#

Since n109n\leq 10^9, it’s usually solved in O(logn)/O(1)O(logn)/O(1).

Inclusion-Exclusion: Horizontal Symmetry + Vertical Symmetry − (Horizontal and Vertical Symmetry)

Horizontal Symmetry: 0,1,3,80,1,3,8 can be arbitrarily combined (they are horizontally symmetric), i.e., 4n4^n.
Vertical Symmetry: There are four possibilities: (2,5),(0,0),(8,8),(5,2)(2,5),(0,0),(8,8),(5,2). They can only be placed with central symmetry.

Note: (1,1)(1,1) cannot be placed; in the calculator display, it is right-aligned and not symmetric.

If nn is odd, the middle position can only be 00 or 88, so the answer is 4n/2×24^{n/2}\times2. If even, it is 4n/24^{n/2}. Simplified, odd and even can be combined into 2n2^n.

Need to subtract the double-counted part that is both horizontally and vertically symmetric. Only (0,0),(8,8)(0,0),(8,8) are double-counted when placed arbitrarily. This part is 2n/22^{\lceil{n/2}\rceil}.

The answer is 4n+2n2n2\displaystyle 4^n+2^n-2^{\lceil{\frac{n}{2}}\rceil}, solved in O(1)O(1).

void solve() {
    int n;cin >> n;
    cout << (qpow(4, n) + qpow(2, n) + mod - qpow(2, (n + 1) / 2)) % mod;
}
cpp

Nowcoder Weekly Contest 47 - F Huahua’s Map#

The map of City A is an n×mn \times m grid. The character ’#’ represents an obstacle, and ’.’ represents open space. Huahua lives at the top-left corner (1,1)(1,1), and Huahua’s friend Mengmeng lives at the bottom-right corner (n,m)(n,m). 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 (x,y)(x,y) to (x+1,y)(x+1,y), (x1,y)(x-1,y), (x,y+1)(x,y+1), (x,y1)(x,y-1).
Huahua can spend a cost of CiC_i to destroy all obstacles in the ii-th column.
Please calculate the minimum cost for Huahua to go to Mengmeng’s house.

Data range: 1n,m100,1ci1051\leq n,m\leq 100,1\leq c_{i}\leq 10^5

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 (i+1,j+1)(i+1,j+1). The answer is {c++}dp[n - 1][m - 1].

Time complexity: O(n3+n2logn2)O(n^3+n^2\log n^2). Will time out if n,m1000n,m\leq 1000.

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';
}
cpp

Method 2:#

See: Nowcoder Weekly Contest Round 47 Problem Solving Report | Ke Scholar _Nowcoder Blog

Time complexity is O(n2logn2)O(n^2\log n^2). It also passes when n,m1000n,m\leq 1000.

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;
}
cpp

Nowcoder 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 [1,2,3][1,2,3] 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 109+710^9+7.

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 [1,2,3,2][1,2,3,2] include [2,2][2,2], etc. Therefore, an array of size nn has exactly 2n12^n -1 subsequences.

1ai31\leq a_{i}\leq 3

  • (1n1000)(1\leq n\leq 1000)
  • (1n105)(1\leq n\leq 10^5)

Solution#

Yang Hui’s Triangle for Combinations / Inverse Elements / Number Theory

C(n,m)=n!(nm)!×m!C(n,m)=\frac{n!}{(n-m)!\times m!}

Let n1,n2,n3n_{1}, n_{2}, n_{3} be the counts of 1,2,31,2,3 respectively, then:

  • n1=2n1n_{1}=2^{n_{1}}
  • n2=i=0n2(i+1)×C(n2,i)n_{2}=\sum\limits_{i=0}^{n_{2}}(i+1)\times C(n_{2},i)
  • n3=i=0n3(i+1)×C(n3,i)n_{3}=\sum\limits_{i=0}^{n_{3}}(i+1)\times C(n_{3},i)

ans=n1×n2×n31\text{ans=}n_{1}\times n_{2}\times n_{3}-1

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';
}
cpp
const 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';
}
cpp

Nowcoder Weekly Contest 55 - E Little Red’s Sequence Product 2.0#

For an integer sequence {b1,b2,,bm}\{b_1,b_2,\dots,b_m\} of length mm, define fi=b1×b2××bif_i = b_1 \times b_2 \times \cdots \times b_i, i.e., the product of the first ii terms. The weight of this sequence is the number of digits among f1,f2,,fmf_1, f_2, \dots, f_m whose units digit is 66.

Little Red has an integer sequence {a1,a2,,an}\{a_1,a_2,\dots,a_n\} of length nn. She wants to know the sum of the weights of all 2n12^n-1 non-empty subsequences of this sequence.

Solution#

DP

fi,jf_{i,j} represents the number of schemes among the first ii numbers that end with jj.

Let fi,jf_{i,j} be the current state, and fi1,jf_{i-1,j} be the previous state, then:

The current state must include the previous state, i.e., fi,j=fi1,j+f_{i,j}=f_{i-1,j}+\dots

The current number is aia_{i}, then fi,j×ai%10f_{i,j\times a_{i}\%10} means that after adding the current number, it ends with j×ai%10j\times a_{i}\%10. Therefore:

fi,j×ai%10=fi1,j+f_{i,j\times a_{i}\%10}=f_{i-1,j}+\dots

When adding the current number, if it ends with 6, the requirement is met. Suppose this subsequence is {1,,i}\{1,\dots,i\}. Then all sequences with larger indices can include this subsequence. There are nin-i of them, and each can be chosen or not, giving 2ni2^{n-i} 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';
}
cpp

F’s computational geometry hints that I should start learning computational geometry!

Nowcoder Solutions: Winter Contests, Weeklies, and Multi-School
https://fxj.wiki/en/blog/solutions-nowcoder
Author 玛卡巴卡
Published at 2026年3月6日
Comment seems to stuck. Try to refresh?✨