Sul_A.'s blog

By Sul_A., history, 11 months ago, In English

Editorial for some of the new CSES tasks. Tasks that are trivial or too similar to already existing tasks are not included.

Every time I solve a new nontrivial task, I will add it here.

NOTE: ONLY READ THE SOLUTIONS IF YOU ARE COMPLETELY STUCK AND OUT OF IDEAS. CSES tasks are the kinds of tasks you can solve at a random time by random chance. You might read a task today and solve it next week. Or next month. Or next 3 months. So read at your own risk.

Sorting & Searching

Distinct Values Subsequences

Dynamic Programming

Mountain Range
Minimal Grid Path

Range Queries

Visible Buildings Queries
Range Interval Queries
Distinct Values Queries II

Mathematics

Next Prime
Permutation Rounds

Sliding Window Problems

Sliding Window Minimum
Sliding Window Distinct Values
Sliding Window Mode
Sliding Window Mex
Sliding Window Inversions
Alternative solutions

Interactive Problems

Hidden Permutation
Colored Chairs

Advanced Graph Problems

Fixed Length Walk Queries

Additional Problems

Bubble Sort Rounds I
Counting LCM Arrays
Subsets with Fixed Average
Two Array Average

Additional Problems II

GCD Subsets
  • Vote: I like it
  • +58
  • Vote: I do not like it

»
11 months ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

The problem statement of Mountain Range is ambiguous imo. How do you go from mountain a to b when the segments lying in between them are not monotonically decreasing ?
Someone pls explain the problem statement

  • »
    »
    11 months ago, hide # ^ |
     
    Vote: I like it +23 Vote: I do not like it

    If $$$h = [5,1,4,2,3]$$$ you can go from the first mountain to any other mountain.

    • »
      »
      »
      11 months ago, hide # ^ |
      Rev. 2  
      Vote: I like it 0 Vote: I do not like it

      So its a subsequence thing, it makes sense now, thanks :) My Solution

    • »
      »
      »
      10 months ago, hide # ^ |
      Rev. 3  
      Vote: I like it 0 Vote: I do not like it

      The problem still does not make sense to me. Can I travel in any direction? If no, then why is the answer to test case number 4 equal to 200000. If yes, then why is the answer to test case number 1 not equal to 10?

      @Eyes_on_me Sul_A.

    • »
      »
      »
      10 months ago, hide # ^ |
       
      Vote: I like it 0 Vote: I do not like it

      Could you please describe how we can move from first mountain to any other? Best I can think is: 5->4->3->2. Then I can not visit 1 because 4 comes in between 2 and 1

      • »
        »
        »
        »
        10 months ago, hide # ^ |
         
        Vote: I like it 0 Vote: I do not like it

        going from 5 to every mountain means that its possible to visit them, not necessarily in the same path. You can go from 5 to 1 directly. Also answer for 1st testcase is 5 because you can choose the path : 40 -> 35 -> 20 -> 17 -> 15

        It cannot be 10 as if you choose to start at 40 (the max element of the array), you'll have to jump it after some moves to traverse all elements which is not possible, and if you don't choose to start at 40, you can never attain it as its the max element.

        • »
          »
          »
          »
          »
          10 months ago, hide # ^ |
          Rev. 3  
          Vote: I like it 0 Vote: I do not like it

          I'm sorry if I misunderstand, but if I can take more than one paths (e.g. You can go from 5 to 1 directly) i.e. I am allowed to "reset", then can I not always visit every mountain if I just start at the largest mountain? I mean I can 'directly' go to any other mountain from the tallest mountain since it is guaranteed that I will never face a larger obstacle

          • »
            »
            »
            »
            »
            »
            10 months ago, hide # ^ |
            Rev. 2  
            Vote: I like it 0 Vote: I do not like it

            No, you can't reset. In the comment he meant that its possible to visit every mountain through some path. Essentially there are 2 paths possible from mountain 5 :: 5 -> 1 and 5 -> 4 -> 3 -> 2. in the problem you have to find the longest path which is the second one.

            • »
              »
              »
              »
              »
              »
              »
              10 months ago, hide # ^ |
               
              Vote: I like it 0 Vote: I do not like it

              Ah got it, thanks a lot mate

              • »
                »
                »
                »
                »
                »
                »
                »
                10 months ago, hide # ^ |
                Rev. 3  
                Vote: I like it 0 Vote: I do not like it

                Basically u move from mountain a to b where h[a] > h[b] and everything between must be in decreasing order of height from a to b (b can be in either direction of a) now again you continue your journey from b to some c such that the same above conditions also apply for going from b to c ... go until you can and find the max no. of mountain ranges in that range !
                NOTE : 5 4 6 1 you cannot go from 5 to 1 directly (6 is in between) here max answer is 3 (path -> 6 -> 5 -> 4)

                Good Example
    • »
      »
      »
      10 months ago, hide # ^ |
       
      Vote: I like it 0 Vote: I do not like it

      But take care u cannot move from 3 -> 1 or 2 -> 1 bcz 4 is in between

»
11 months ago, hide # |
 
Vote: I like it +4 Vote: I do not like it

Range Interval Queries can be solved in O(NlogN) offline.

Suppose we have have a function f(i, l, r) that calculates how many elements are there with index <= i and value in [l, r]. Now for each query (a, b, c, d) we add two events:

  • at a-1 remove f(a-1, c, d)

  • at b add f(b, c, d)

f(i, l, r) can be calculated in logN with basic fenwick tree for sum.

»
11 months ago, hide # |
 
Vote: I like it +1 Vote: I do not like it

You can solve Sliding Window Or by maintaining counts of each bit. But my solution required using SIMD intrinsics + pragmas to pass.

»
11 months ago, hide # |
 
Vote: I like it +11 Vote: I do not like it

About the solution of next prime, it's not correct to use average prime gap to estimate complexity since the test cases are not necessarily generated randomly, and the upper bound of prime gap should be used. And I doubt Miller-Rabin test can be run in just one log factor. the implementation from KACTL seems to have 2~3 log factors depending on whether you think size of $$$A$$$ as constant.

»
11 months ago, hide # |
 
Vote: I like it -8 Vote: I do not like it

First problem in the Interactive Problems section requires log n queries instead of n log n. Imo binary search would be much easier to implement in this problem.

  • »
    »
    11 months ago, hide # ^ |
    Rev. 2  
    Vote: I like it 0 Vote: I do not like it

    How do you solve Hidden Permutation using binary search?

    • »
      »
      »
      11 months ago, hide # ^ |
       
      Vote: I like it 0 Vote: I do not like it

      I am sorry, mixed it with another problem

    • »
      »
      »
      10 months ago, hide # ^ |
      Rev. 2  
      Vote: I like it 0 Vote: I do not like it

      Build the answer by prefix.

      Consider the following algorithm:

      Goal: Label the prefix $$$[1, i]$$$ with labels $$$[1, i]$$$, while preserving the relative ordering of the elements. The answer will be complete when we successfully label the entire prefix $$$[1, n]$$$.

      Base Case:

      $$$a[1] = 1$$$

      Inductive Step:

      Assume we have already labeled the prefix $$$[1, i - 1]$$$ using labels from $$$[1, i - 1]$$$, such that the relative ordering with respect to the actual permutation is preserved for all indices $$$j, k \lt i$$$.

      Now we want to extend the labeling to include the $$$i$$$th index. One way to do this is via binary search: We need to find the leftmost number $$$k \in [1, i]$$$ such that $$$a[i] \lt k$$$.
      Then we set $$$a[i] = k$$$, and increment all existing labels from the prefix $$$[1, i - 1]$$$ that are greater than or equal to $$$k$$$.
      If no such $$$k$$$ exists, then we set $$$a[i] = i$$$.
      This step takes $$$\log(i)$$$ queries.

      Reference Code: https://cses.fi/paste/b4b9437e5ed90652ca32d9/

    • »
      »
      »
      9 months ago, hide # ^ |
       
      Vote: I like it 0 Vote: I do not like it
      // 6
      // YES
      // YES
      // NO
      // NO
      // NO
      // YES
      // NO
      // NO
      // NO
      // ? 1 2
      // ? 1 3
      // ? 2 3
      // ? 3 4
      // ? 1 4
      // ? 1 5
      // ? 3 5
      // ? 5 6
      // ? 4 6
      // ! 3 6 5 2 4 1
      void solve()
      {
          ll n;
          cin >> n;
          vi v;
          v.pb(1);
          iloop(i, 2, n + 1)
          {
              ll low = 0, high = v.size() - 1;
              while (low <= high)
              {
                  ll mid = (low + high) / 2;
                  cout << "?" << sp << v[mid] << sp << i << endl;
                  cout.flush();
                  string s;
                  cin >> s;
                  if (s == "YES")
                      low = mid + 1;
                  else
                      high = mid - 1;
              }
              v.insert(v.begin() + low, i);
          }
          vi ans(n, 0);
          ll c = 1;
          for (auto x : v)
              ans[x - 1] = c++;
          cout << "! ";
          print(ans);
      }
      
»
11 months ago, hide # |
Rev. 2  
Vote: I like it 0 Vote: I do not like it
Spoiler for Mountain Ranges
»
11 months ago, hide # |
 
Vote: I like it +8 Vote: I do not like it
Spoiler for Hidden Permutation
  • »
    »
    11 months ago, hide # ^ |
    Rev. 2  
    Vote: I like it +8 Vote: I do not like it

    Why does std::sort not work?

    Edit: With the help of PeruvianCartel's comment and some independent reseach I did on the day itself, it seems as straightforward as STL's implementation of std::sort uses quick sort whereas std::stable_sort uses merge sort.

  • »
    »
    11 months ago, hide # ^ |
     
    Vote: I like it +19 Vote: I do not like it

    for anyone doesn't know, stable sort, which is basically merge sort, only have to perform a pretty low number of comparisons. It's not optimal, but it's there (the theoretical optimal number of comparison to sort an array of 1000 elements is 8530, and merge sort accomplish that in 8977, while quick sort accomplish that in around 11000).

»
11 months ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

Binary lifting is not needed in "Visible Building Queries", just answer queries offline and binary search on the stack.

https://cses.fi/paste/92acd924a955ed05c4ba93/

»
11 months ago, hide # |
 
Vote: I like it +1 Vote: I do not like it

Mountain Range can be solved without segment tree, here's my submission with comments Submission

»
11 months ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

Any hints for Minimal Grid Path, string hashing is useless here!

  • »
    »
    11 months ago, hide # ^ |
     
    Vote: I like it 0 Vote: I do not like it

    I think you already knew that if right cell is 'A' below one is 'B' then you must only go right cuz that only way to get lexicographically minimum walk from there you can do some form of graph traversal like bfs to construct optimum walk try it

    • »
      »
      »
      11 months ago, hide # ^ |
      Rev. 2  
      Vote: I like it 0 Vote: I do not like it

      what about grid like below?

      AAAD
      BACA
      CBCA

      I don't think greedy works here.

      • »
        »
        »
        »
        11 months ago, hide # ^ |
         
        Vote: I like it 0 Vote: I do not like it

        like from your (1,1) the only possible position is to go (1,2) rigth cuz the (2, 1) is B, then from that(1, 2) it could either go right or down right cuz that both 'A' then I add both position it to my queue then consider the next level it could either be 'D', 'C' or 'B' that extend from the past level then I extend to 'B' and so on like construct it by level, btw the code got accepted if you got counter test that you suspect I'll try

      • »
        »
        »
        »
        8 months ago, hide # ^ |
         
        Vote: I like it 0 Vote: I do not like it

        if you iterate diagonal by diagonal then you can look at the cells in the next diagonal and only consider those with minimum value. there are at most n cells in a diagonal so the code runs in O(n^2)

    • »
      »
      »
      10 months ago, hide # ^ |
       
      Vote: I like it 0 Vote: I do not like it

      looks like greedy , but i wonder why it is marked as Dp in the problemset

  • »
    »
    11 months ago, hide # ^ |
     
    Vote: I like it 0 Vote: I do not like it

    Bfs is correct on this one (You remove all path that is not optimal straight away)

  • »
    »
    11 months ago, hide # ^ |
     
    Vote: I like it 0 Vote: I do not like it

    I could do it within time limit by simple bfs and maintaining a visited array.

  • »
    »
    11 months ago, hide # ^ |
     
    Vote: I like it 0 Vote: I do not like it

    My BinLift+StringHashing gave MLE . Then saw that we can find the optimal path using level order BFS

  • »
    »
    11 months ago, hide # ^ |
     
    Vote: I like it +1 Vote: I do not like it

    It's simply a BFS starting at node (0, 0)

  • »
    »
    10 months ago, hide # ^ |
     
    Vote: I like it 0 Vote: I do not like it

    BFS Solution

    #include <bits/stdc++.h>
    #include <ext/pb_ds/assoc_container.hpp>
    using namespace std;
    using namespace __gnu_pbds;
    
    template <class T> using ordered_set = tree<T, null_type, less<T>, rb_tree_tag,tree_order_statistics_node_update>;
    // os.insert(element)
    // os.erase(element)
    // os.find_by_order(k) {iterator to the k'th element 0 indexing}
    // os.order_of_key(k) {count of elements smaller than k}
    
    #define fastio ios::sync_with_stdio(false);cin.tie(NULL)
    #define int long long
    #define endl '\n'
    int INF = 1e18;
    int NINF = -1e18;
    int MOD = 1000000000+7;
    
    void solve();
    
    int32_t main()
    {
        fastio;
        int tests = 1;
        // cin >> tests;
        while(tests--)
        {
            solve();
        }
        return 0;
    }
    
    void solve()
    {
        // input
        int n;
        cin >> n;
    
        vector<string> grid(n);
        for(int i=0; i<n; i++)
            cin >> grid[i];
        
        // solution
        string res;
    
        queue<pair<int, int>> q;
        q.push({0, 0});
    
        bool vis[n][n];
        memset(vis, false, sizeof(vis));
        vis[0][0] = true;
    
        while(!q.empty())
        {
            int sz = q.size();
    
            queue<pair<int, int>> qq(q);
            auto [i, j] = qq.front();
            char mnc = grid[i][j];
            while(!qq.empty())
            {
                auto [i, j] = qq.front();
                qq.pop();
                mnc = min(mnc, grid[i][j]);
            }
    
            res.push_back(mnc);
    
            while(sz--)
            {
                auto [i, j] = q.front();
                q.pop();
                char c = grid[i][j];
                if(c == mnc)
                {
                    if(i+1<n && !vis[i+1][j])
                    {
                        vis[i+1][j] = true;
                        q.push({i+1, j});
                    }
                    if(j+1<n && !vis[i][j+1])
                    {
                        vis[i][j+1] = true;
                        q.push({i, j+1});
                    }
                }
            }
        }
        cout << res;
    }
    
  • »
    »
    9 months ago, hide # ^ |
     
    Vote: I like it 0 Vote: I do not like it
    #include <bits/stdc++.h>
    using namespace std;
    
    #define int long long
    #define ARUN ios::sync_with_stdio(false); cin.tie(nullptr);
    
    int32_t main() {
        ARUN;
        int n;
        cin >> n;
        vector<vector<char>> mat(n, vector<char>(n));
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                cin >> mat[i][j];
    
        queue<pair<int, int>> q;
        vector<vector<int>> vis(n, vector<int>(n, 0));
        q.emplace(0, 0);
        vis[0][0] = 1;
        string ans = string(1, mat[0][0]);
        while (!q.empty()) {
            int s = q.size();
            char mini = 'Z';
            vector<pair<int, int>> tmp;
            while (s--) {
                auto [x, y] = q.front();
                q.pop();
                auto nextState = [&](int nx, int ny) {
                    if (nx >= n || ny >= n || vis[nx][ny]) return;
                    vis[nx][ny] = 1;
                    tmp.emplace_back(nx, ny);
                    mini = min(mini, mat[nx][ny]);
                };
                nextState(x + 1, y);
                nextState(x, y + 1);
            }
            if (tmp.empty()) break;
            for (auto& [x, y] : tmp) {
                if (mat[x][y] == mini) {
                    q.emplace(x, y);
                }
            }
            ans += mini;
        }
    
        cout << ans << '\n';
        return 0;
    }
    
    
»
11 months ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

can someone give me segment tree(doesnt matter if it is lazy or regular) problems that are on codeforces?

»
11 months ago, hide # |
Rev. 4  
Vote: I like it 0 Vote: I do not like it

For the Range Interval Queries, I'm struggling to find out why my implementation of Merge Sort Tree gets TLE

https://cses.fi/paste/f21d39c5ee195b1bc607b8/

In fact, I solved it using Wavelet Tree and after I tried submitting the official solution from CSES that uses Merge Sort Tree and even their code gets TLE as well

Any thoughts?

»
11 months ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

Mountain Range I don't use segment tree. This is my code https://cses.fi/paste/902973a8389f6ae2c6bd6a/

»
11 months ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

Can someone explain me how do we use segment tree for finding mode in a given interval?

»
10 months ago, hide # |
Rev. 3  
Vote: I like it 0 Vote: I do not like it

can anyone pls share their Binary lifting solution of Visible building queries (from range queries), I am facing TLE on one test case,

my code : https://cses.fi/paste/079399dd9980b4b8c9ea9c/

»
10 months ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

Thank you very much!

»
10 months ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

can anyone help me with Sliding Window Advertisement and Xor Pyramid Row.

  • »
    »
    10 months ago, hide # ^ |
     
    Vote: I like it 0 Vote: I do not like it

    For xor pyramid row, look at the case where k=2^something. Then, for the general case, just write k as sum of powers of 2.

    • »
      »
      »
      10 months ago, hide # ^ |
       
      Vote: I like it 0 Vote: I do not like it

      I'm very bad with bits, can you elaborate more?

      • »
        »
        »
        »
        10 months ago, hide # ^ |
         
        Vote: I like it 0 Vote: I do not like it

        Sorry, I meant the case where n-k is a power of 2.

        Solution for n-k=power of 2
        Full solution
»
10 months ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

Can anyone tell me the correct problem statement of Mountain Range I am not able to understand it

  • »
    »
    10 months ago, hide # ^ |
     
    Vote: I like it 0 Vote: I do not like it

    There are n mountains in a row, each with a specific height. You can start from any mountain, you can go from mountain a to mountain b if height a is strictly greater than height b and all of mountains in that range([a, a+1, a+2, ..., b] you can go to b if h[a] > max(h[a+1], h[a+2], ... h[b] same thing if a > b). and now the question is what is the maximum number of mountains you can visit on your route?

    consider this array: [20, 15, 17, 35, 25, 40, 12, 19, 13, 12], if you start from 5th mountain you cant go, but if you start from 8 mountain you can go to 7, 9 and 10 mountains.

»
10 months ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

For Distinct Values Subsequences, remember to subtract 1 to account for the empty subsequence

»
10 months ago, hide # |
 
Vote: I like it +8 Vote: I do not like it

Here is my solution for the Mountain Range, it's a simple solution (no segment tree/fenwik tree/any new sorting techniques). just start from the highest mountain and run a dp such that i'th index is updated using the nearest higher mountain at left and right of it(if they exist).

#include <bits/stdc++.h>
using namespace std;
// typedef long long ll;
// #define int ll

void solve(int tc = 0) {
    int n;
    cin >> n;
    std::vector<int> v(n), l(n, -1), r(n, -1), ls(n, -1), rs(n, -1);
    std::vector<pair<int, int>> p(n);
    for (int i = 0; i < n; i++) {
        cin >> v[i];
        p[i] = {v[i], i};
    }
    sort(p.rbegin(), p.rend());
 
    stack<int> st;
    for (int i = 0; i < n; i++) {
        while (!st.empty() && v[st.top()] <= v[i]) {
            st.pop();
        }
        if (!st.empty())  {
            l[i] = st.top();
        }
        st.push(i);
    }
 
    while (!st.empty()) {
        st.pop();
    }
 
    for (int i = n - 1; i >= 0; i--) {
        while (!st.empty() && v[st.top()] <= v[i]) {
            st.pop();
        }
        if (!st.empty())  {
            r[i] = st.top();
        }
        st.push(i);
    }


    vector<int> dp(n, 1);

    for (auto &[x, y] : p) {
        if (r[y] != -1) {
            dp[y] = max(dp[y], dp[r[y]] + 1);
        }
        if (l[y] != -1) {
            dp[y] = max(dp[y], dp[l[y]] + 1); 
        }
    }

    cout << *max_element(dp.begin(), dp.end());
 
 
}
 
int32_t main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
 
    int O_O = 1;
    // cin >> O_O;
    while (O_O--) {
        solve();
        cout << "\n";
    }
 
    return 0;
}
»
10 months ago, hide # |
Rev. 2  
Vote: I like it 0 Vote: I do not like it

I don't seem to understand the Mountain Range statement quite well.

Could anyone explain to me this test case from cses:

Spoiler
  • »
    »
    10 months ago, hide # ^ |
     
    Vote: I like it +1 Vote: I do not like it

    You can go both left and right. So the path is 89, 87, 77, 59, 41, 32,22

    • »
      »
      »
      10 months ago, hide # ^ |
       
      Vote: I like it +1 Vote: I do not like it

      it make sense, thank you !

      • »
        »
        »
        »
        10 months ago, hide # ^ |
         
        Vote: I like it 0 Vote: I do not like it

        why we can't jump from the last element 89 to first one 3 , as all the elements b/w them are lesser than 89 , i'm confused !

        • »
          »
          »
          »
          »
          10 months ago, hide # ^ |
           
          Vote: I like it 0 Vote: I do not like it

          yes you can jump from 89 to 3, but the elements in between are not counted in the answer, only 89 and 3 are visited, after this you should look for the next jump.

          basically you can jump in any direction as long as the condition is met.

          That's what I didn't get in the beginning.

»
10 months ago, hide # |
 
Vote: I like it +4 Vote: I do not like it
Fixed Length Walk Queries
»
10 months ago, hide # |
Rev. 2  
Vote: I like it +3 Vote: I do not like it

I have not seen anyone posting construction section, here are my solutions to some of them (couldn't solve last 3)

Inverse Inversions

solution
code

Monotone Subsequences

solution
code

Third Permutation

solution
code

Permutation Prime Sums

solution
code

Chess Tournament

solution
code

I would be really thankful if someone tell me how to solve Distinct Sums Grid

»
10 months ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

Can anyone show me how to solve Hidden Permutation using merge sort?

»
10 months ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

please provide the full solution of Hidden Permutation

»
10 months ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

Hi, I was trying to solve the problem Advanced Graph — Course schedule 2 : https://cses.fi/problemset/task/1757,

My approach is follows :

If we have to do course "a" before course "b", then add a edge from b->a in the graph .

Now in this graph run DFS for each component and keep a track of the minimum node value you have in the subtree.

Now, sort the adj list based on the minimum node value in each subtree, so that If there a multiple ways to do projects "i" then I greedily choose the branch that would lead to do the next-smallest option available as the question requires

Now once, I have sorted the adj_list , I run a dfs and push the node in the result vector once you have traverse all of it's children , this is done in dfs2

I couldn't figure what is wrong in my code, it fails one test-case on CSES, also I believe the run time is O(n+nlogm), so it should pass given the constraints but it gives TLE on one test case

My code link : https://cses.fi/paste/3febffc363f54010ceed11/

»
10 months ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

In the Range Interval Queries problem, I tried merge sort tree with fractional cascading to make the queries in 2 * log(n) but it still gives TLE. Here is my code

»
9 months ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

Range Interval Queries can also be solved using Binary Indexed Tree.

#elements with index in range [l, r]

= #elements in the whole array

- #element in the range [1, l — 1]

- #element in the range [r+1, n]

Each item on the right of the equation can be calculated separately with sorting of the queries.

»
9 months ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

For mountain range for every element you can come on it from either the nearest element on left greater than it or the nearest element on right that is greater than it so we take max of these two this can be implemented in o(n) so a better solution ig

»
8 months ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

Isn't the solution to the Minimal Grid Path problem derivable using BFS? Writing a DP solution for it feels quite unintuitive.

  • »
    »
    7 months ago, hide # ^ |
     
    Vote: I like it 0 Vote: I do not like it

    dp is pretty intuitive for it (because of similar problems like Grid Paths I) but it fails because of O(n) string comparison. bfs is the solution as you noticed.

»
8 months ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

Can someone please give a detailed explanation of what SegTree node is going to store in distinct value queries 2 ? if SegTree is going to be of minimum Si for an interval , then how will we manage updates fast ?

  • »
    »
    7 months ago, hide # ^ |
    Rev. 2  
    Vote: I like it 0 Vote: I do not like it

    Sure, let $$$\text{next}[i]$$$ be the index of the next occurence of $$$a[i]$$$. Then do you see how ensuring that $$$\min({\text{next}[l]\dots \text{next}[r]}) \gt r$$$ ensures that the next occurence of any element in $$$[l,r]$$$ occurs after $$$r$$$, thus ensuring that $$$a[l]\dots a[r]$$$ contains distinct elements? The solution is to maintain $$$\text{next}[i]$$$ with a segment tree (to allow for efficient $$$\min$$$ queries), dynamically updating the two places it changes on every update.

    Implementation: https://cses.fi/paste/d2e6d3cc7abc11eec468c5/

    • »
      »
      »
      6 months ago, hide # ^ |
       
      Vote: I like it 0 Vote: I do not like it

      Hey, I am using the same approach but I am getting TLE. Could you find what's wrong with my implementation?

      Should I use the segtree implementation that takes $$$O(2n)$$$ space (like you did)?

      • »
        »
        »
        »
        6 months ago, hide # ^ |
         
        Vote: I like it 0 Vote: I do not like it

        Stop using std::unordered_map. Use coordinate compression like I did.

        • »
          »
          »
          »
          »
          6 months ago, hide # ^ |
           
          Vote: I like it 0 Vote: I do not like it

          I've tried that too. This still gave me a TLE.

          • »
            »
            »
            »
            »
            »
            6 months ago, hide # ^ |
             
            Vote: I like it 0 Vote: I do not like it

            Alright, let me have a closer look. Hold on

          • »
            »
            »
            »
            »
            »
            6 months ago, hide # ^ |
            Rev. 2  
            Vote: I like it 0 Vote: I do not like it

            Alright, I had a closer look. You're still using std::unordered_map for coordinate compression itself. Tip: never use that. Ever. Try coordinate compressing using the buf + std::unique + std::lower_bound trick (if you haven't seen this yet, it's worth checking out)

            Edit: I just saw that you are indeed using that trick. Nice. Just remove the map and use std::lower_bound instead and that should fix it.

            • »
              »
              »
              »
              »
              »
              »
              6 months ago, hide # ^ |
               
              Vote: I like it 0 Vote: I do not like it

              Making this change got it accepted. Thanks for the tip. I was aware about hashing collisions that can lead to $$$O(n)$$$ but I guess I underestimated it :|

»
5 months ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

For "Visible Building Queries". I think I did something totally different than binary lifting https://cses.fi/paste/7ad0015ccbfbb625eaafe3/

I firstly, used segment tree to store the visible buildings list at each node (kind of merge sort tree), by nature of the constraint they will be sorted.

Now to query (L,R), First get the answer from the LEFT subtree, without any constraint, but for the right subtree, there is a constraint that only elements larger than the MAX of left subtree will be visible. So we propagate this threshold to the right subtree after computing the left subtree and then finally we merge both of the answers from left and right.

  • »
    »
    4 months ago, hide # ^ |
     
    Vote: I like it 0 Vote: I do not like it

    Code Link

    I have also did a similar type of thing, i haven't created the merge sort trees I have used the pre-calculated answers from the left section to calculate the visible building in right subtree and finally store the height and visible building in the parent node.

    This approach is space optimized.

»
4 months ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

For Minimal Grid Path in DP section. Here each (x,y) goes atmost once in queue and atmost twice in vector f. So its O(n^2). Let me know if I'm wrong in TC. Note: Its Accepted in CSES.

// this is code

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define mod 1000000007

int binpow(int a,int b,int m)
{
    int res=1;
    a=a%m;
    while (b!=0){
        if (b&1){
            res=(res*a)%m;
        }
        a=(a*a)%m;
        b=b>>1;
    }
    return res;
}


void solve()
{
    int n;cin>>n;
    int a[n][n];
    for (int i=0;i<n;i++){
        for (int j=0;j<n;j++){
            char ch;cin>>ch;
            a[i][j]=ch-'A';
        }
    }
    queue <array<int,2>> q;
    q.push({0,0});
    char ch='A'+a[0][0];
    cout<<ch;
    vector vis(n,vector<bool>(n));
    vis[0][0]=true;
    while (!q.empty()){
        int sz=q.size();
        vector <array<int,3>> f;
        while (sz--){
            auto [x,y]=q.front();
            q.pop();
            if (x+1<n && !vis[x+1][y]){
                while (!f.empty() && a[x+1][y]<f.back()[0]) f.pop_back();
                if (f.empty() || f.back()[0]==a[x+1][y]) f.push_back({a[x+1][y],x+1,y});
            }
            if (y+1<n && !vis[x][y+1]){
                while (!f.empty() && a[x][y+1]<f.back()[0]) f.pop_back();
                if (f.empty() || f.back()[0]==a[x][y+1]) f.push_back({a[x][y+1],x,y+1});
            }
        }
        if (f.empty()) break;
        char ch='A'+f.back()[0];
        cout<<ch;
        for (auto [c,x,y]:f){
            if (!vis[x][y]){
                //cout<<x<<" "<<y<<'\n';
                q.push({x,y}),vis[x][y]=true;
            }
        }
    }
    cout<<"\n";
}
int32_t main()
{
    ios_base::sync_with_stdio(0); cin.tie(0);cout.tie(0);
    int t=1;
    //cin>>t;
    while (t--){
        solve();
    }
    return 0;
}



»
4 months ago, hide # |
Rev. 2  
Vote: I like it 0 Vote: I do not like it

Thanks will be useful!!

»
4 months ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

https://cses.fi/paste/86e988fee98ea502edda28/

For the range interval queries, my solution which is O(q(logn)^2) giving TLE while submission.