ABalobanov's blog

By ABalobanov, 5 months ago, translation, In English

Thank you all for participation! We hope, you enjoyed the problems.

2176A - Operations with Inversions

Hints
Solution
Implementation

2176B - Optimal Shifts

Hints
Solution
Implementation

2176C - Odd Process

Hints
Solution
Implementation

2176D - Fibonacci Paths

In this Editorial, we will refer to simple paths in the graph, where the sequence of numbers forms a generalized Fibonacci sequence, as Fibonacci paths.

Hints
Solution
Implementation

2176E - Remove at the lowest cost

Hints
Solution without queries
Hint 3
Solution with queries
Implementation

2176F - Omega Numbers

Hints
Solution
Implementation

Tutorial of Codeforces Round 1070 (Div. 2)

  • Vote: I like it
  • +139
  • Vote: I do not like it

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

Auto comment: topic has been updated by ABalobanov (previous revision, new revision, compare).

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

Writing first so 123gjweq2 can't say first

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

I couldn't understand the tutorial code, so here's a (maybe) simpler top-down DP implementation with a very similar idea (compressing edge state into (end node index, start node value) pairs) for those like me. 353122473

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

I thought of a different solution for problem D that barely passed in time.

Observe that the value written at a certain vertex is at most $$$10^{18}$$$. Therefore, no generalized Fibonacci path is longer than $$$86$$$ nodes, as the $$$87$$$-th non-generalized Fibonacci number is greater than $$$10^{18}$$$ (and this should hold for any other larger starting numbers than both being $$$1$$$). This can easily be checked with a program that calculates the first $$$n$$$ Fibonacci numbers.

Thus, we can store for each node the amount of paths that require the next node in a path to have a certain value, which is given by the sum of the value at the node and each adjacent node entering it, calculated in the previous iteration. Initially, accounting for paths of length 2, we can store at the destination of each edge all the sums between the value of that node and any node entering it, counting possibly repeated sums.

For convenience I used the reversed graph, as that way I could just check for a each node in an iteration if its value is present at the map of sums computed in the previous iteration for each of the outgoing nodes. Though that was just a decision I made while implementing during the contest.

Due to the initial observation, there would be at most $$$87$$$ iterations over all the nodes and edges. Also, by using a map to lookup and update values present at a certain destination, I have a $$$\log$$$ factor in my solution to account for.

Hence, the complexity of this solution should be around $$$O(87 \cdot (n+m) \log m)$$$, considering in each iteration at most $$$m$$$ distinct sums would be computed (one for each edge), amounting to around $$$6.5 \cdot 10^8$$$ operations (explaining why my solution barely passed the TL). Also, I may be off in the exact numbers, but the general idea is that "Fibonnaci paths are short".

Here's my submission: 353082932

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

    I tried to make use of the same idea (paths have length at most $$$87$$$) in some of my initial submissions but got TLE. After that, I realised I can just sort the vertices by $$$a_i$$$ and compute the DP in that order, so I very quickly modified the code to make it pass. Even the for-loop over the lengths is still in there!

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

      Yup, after reading the editorial I got the idea of sorting edges by value in their destination, and I modified the submission I posted above. It passed in just 0.2s. The code is identical apart from that: 353380486

      While in contest I also got a TLE, so I changed to a newer compiler, optimized access to maps a bit to avoid sometimes accessing two times unnecessarily, and crossed my fingers haha. Glad I got a bit lucky.

      Nevertheless, I thought the idea was neat and worth mentioning.

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

Here is my two pass greedy linkedlist solution for E:

https://mirror.codeforces.com/contest/2176/submission/353120120

O(Nlog(N)) because of an initial sort, otherwise O(N).

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

can anyone help me with problem D?

https://mirror.codeforces.com/contest/2176/submission/353126337

whats wrong here?intuitively seems perfect but getting wa on test 1 itself

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

Why my code fail on C.

#include <bits/stdc++.h>

#define int long long

using namespace std;

typedef long long ll;

const int N = 2e5 + 10;

int t, n;
ll res[N];

signed main() {
    cin >> t;
    while (t -- ) {
        vector<ll> odd, even;

        cin >> n;
        for (int i = 1; i <= n; ++ i) {
            int x;
            cin >> x;
            if (x & 1) odd.push_back(x);
            else even.push_back(x);
        }

        sort(even.begin(), even.end(), [](int x, int y) {
            return x > y;
        });
        sort(odd.begin(), odd.end(), [](int x, int y) {
            return x > y;
        });

        int l1 = even.size(), l2 = odd.size();
        if (!l2) {
            for (int i = 1; i <= n; ++ i)
                cout << 0 << " " ;
            puts("");
            continue;
        }
        memset(res, 0, sizeof res);
        res[1] = odd[0];
        for (int i = 0; i < l1; ++ i) res[i + 2] = res[i + 1] + even[i];
        // 偶数用完了 
        if (l2 & 1) {
            for (int i = l1 + 2; i <= n; ++ i)
                res[i] = res[i - 2];
        } else res[n] = 0;

        for (int i = 1; i <= n; ++ i)
            cout << res[i] << " " ;
        puts("");
    }

    return 0;
}
  • »
    »
    5 months ago, hide # ^ |
     
    Vote: I like it 0 Vote: I do not like it

    what if we do not have enough evens :)

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

      If even is used up, we gonna used $$$2$$$, $$$3$$$, $$$4$$$, …… odd numbers. But we don't want to use even times of odd numbers, let number of even number is $$$m$$$, when $$$k = m + 2$$$,i use three odd number and remove a minimum even number, when $$$k = m + c$$$ which $$$c$$$ is an odd number, the answer equals to $$$res_{m + 1}$$$. Why my code fail?

              if (l2 & 1) {
                  for (int i = l1 + 2; i <= n; ++ i)
                      res[i] = res[i - 2];
              } else res[n] = 0;
      
    • »
      »
      »
      5 months ago, hide # ^ |
       
      Vote: I like it 0 Vote: I do not like it

      I get it. When I was modifying the code, I forgot to put this for loop outside the if statement.

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

I have a slightly different approach to D. I simply used DFS and memoization to find the answer. Since using map would give MLE (353062066), I used unordered map with custom hash function (353064160), which reduced the memory by a lot.

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

Here is my solution to Problem D: Due to the rapid growth rate of Fibonacci, we can use DFS to calculate each Fibonacci number brute-force, and incorporate memoization to solve this problem. 353130807

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

having hints before main solution is really helpful, thanks

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

Convolution solution to F:

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

In problem C, what is m?

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

Can someone tell why my code is giving wrong answer on test case 2 or give a test case where my code fails

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
using ll = long long;
void solve(){
    ll n;
    cin>>n;
    vector<ll>a(n);
    vector<ll>odd;
    vector<ll>even;
    for(ll i=0;i<n;i++){
        cin>>a[i];
        if(a[i]%2==0)
            even.push_back(a[i]);
        else
            odd.push_back(a[i]);
    }
    sort(odd.begin(),odd.end(),greater<ll>());
    sort(even.begin(),even.end(),greater<ll>());
    vector<ll>prefixsum(even.size()+1,0);
    for(ll i=1;i<even.size()+1;i++){
        prefixsum[i]=prefixsum[i-1]+even[i-1];
    }
    ll s = even.size()+1;
    vector<ll>val(n+1);
    for(ll k=1;k<=min(n,s);k++){
           val[k] = odd.empty() ? 0 : odd[0] + prefixsum[k-1];
    }
    for(ll k=s+1;k<=n;k+=2){
        if(even.size()==1)
            val[k]=0;
        else{
            if(s - 1 >= 1)
                val[k] = val[s - 1];
            else 
                val[k] = 0;
        }
    }
    for(ll k=s+2;k<=n;k+=2){ 
            val[k] = val[s];
    }
    if(odd.size()%2==0 && even.size()%2==0)
        val[n]=0;
    for(ll i=1;i<=n;i++){
        cout<<val[i]<<" ";
    }
    cout<<endl;
}
int main(){
    int t;
    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}
  • »
    »
    5 months ago, hide # ^ |
     
    Vote: I like it +3 Vote: I do not like it

    I have found your bug!

    Its because you had this line: if(even.size()==1) val[k]=0

    The counterexample is this case

    n=5

    a = {1, 1, 1, 1, 2}

    The AC code outputs: 1 3 1 3 0 But your code outputs: 1 3 0 3 0

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

E can be solved using segment tree beats.

For each i find l,r which is the widest range (including i) that have values <=a[i] (using stack). Then update the cost for removing each element in range l to r by assigning it to min(cost[j],c[i]) for which we use segtree beats. Initial answer would be sum of cost for all minus cost for last remaining element (which is minimum of c[j] where a[j]==max(a)). For zeroing operations, you use l,r of that element and update cost[j] to min(cost[j],0) and again find the sum of all costs. Once you have zeroed any index such that a[i]==max(a) all further costs will be 0.

This solution can be used to solve for a type of updation query where you reduce c for any element.

»
5 months ago, hide # |
Rev. 2  
Vote: I like it -22 Vote: I do not like it

can anyone tell me, what is the error in this code ~~~~~ // this is code

include<bits/stdc++.h>

using namespace std; typedef long long ll; int main() { ll t,n,i,odd,even,sum,k,check; cin>>t; while(t--) { cin>>n; ll array[n]; odd=0,even=0; vectorodds,evens; for(i=0;i<n;i++) { cin>>array[i]; if(array[i]%2==1) { odd++; odds.push_back(array[i]); } else { even++; evens.push_back(array[i]); } } sort(odds.begin(),odds.end(),greater()); sort(evens.begin(),evens.end(),greater()); vectorpresum; sum=0; for(i=0;i<evens.size();i++) { sum+=evens[i]; presum.push_back(sum); } if(odd==0) { for(i=1;i<=n;i++) cout<<0<<" "; cout<<endl; } else if(even==0) { for(i=1;i<=n;i++) { if(i%2==1) cout<<odds[0]<<" "; else cout<<0<<" "; } cout<<endl; } else { if(odd==1) { cout<<odds[0]<<" "; for(i=0;i<presum.size();i++) cout<<odds[0]+presum[i]<<" "; cout<<endl; } else if(odd==2) { cout<<odds[0]<<" "; for(i=0;i<presum.size();i++) cout<<odds[0]+presum[i]<<" "; cout<<0<<" "<<endl; } else {// odds>=3 cout<<odds[0]<<" "; for(i=0;i<presum.size();i++) cout<<odds[0]+presum[i]<<" "; k=1+presum.size(); check=(k%2); for(i=k+1;i<=n;i++) { if((i%2)==check) cout<<odds[0]+presum[presum.size()-1]<<" "; else cout<<odds[0]+presum[presum.size()-2]<<" "; } cout<<endl; } } } return 0; } ~~~~~

»
5 months ago, hide # |
Rev. 2  
Vote: I like it +1 Vote: I do not like it

A nice observation can make code for C easier. Here is my submission 353059457 Following the nomenclature in tutorial since for k=m+2 we are using oc and all even except mth therefore it is same for k=m and again for k=m+3 it is same as k=m+1 and so on. All edge cases considered separately — All odd, no odd and even no.of odds.

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

The hints of problem c are very good.

I like it how he explain all the cases in problem c.

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

I saw 998345353 at F when I was using a translate plugin. Who proposed the idea? Great!

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

For E there is a O(n) solution, you do cartesian tree and color the subtree of a node each time, with ascending c[i]'s. The only caveat is if a[node] == a[par[node]] you should start coloring from par[node] so for that I hold a link array which gets us to the highest node with the same value as the current one. Here is my solution : https://mirror.codeforces.com/contest/2176/submission/353155958

note : I did the sorting with std::sort for convenience but you can do that with counting sort to get true O(n)

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

In Problem D, why we should sort the edges by $$$a_u+a_v$$$?

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

    if you have a simple path and it follows the definition of fibonacci sequence, and without loss of generality lets assume if edge (u1,v1) comes before edge (u2, v2) then its sum should also be in the same order.

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

I spent quite a bit of time on Problem B, only to see a three-line solution in the editorial…

For reference, this is the method I used:

  • Find the shortest consecutive zero segment (length = d).
  • Shift the string by d and do a bitwise OR with the original.
  • Repeat until there are no zeros left.

Here’s my submission:B — Optimal Shifts

Can anyone confirm if this actually minimizes the number of operations (not the cost)? Would feel better knowing I wasn’t overcomplicating things.

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

It turns out there is no need for 87 or 90 bound needed in problem $$$D$$$. The problem doesn't guarantees that the given graph is DAG , but we can still make it a DAG. Note that the sequence is increasing except for the first two elements. Hence make a second graph , which has an edge from $$$u$$$ to $$$v$$$ iff $$$a[v] \gt a[u]$$$. You can look at my submission 353070891

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

why is my solution failing in problem D

my code : 353225582

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

For C I think you it doesn't matter which odd number it is, except for the maximum. If at least one odd exists, you could first print the maximum odd number and then m more numbers where the ith number will be maxOdd+ith even number (in descending order) and then for the remaining numbers: m+2 to n, for jth number if (j-m) is odd print the (sum of all even+maxOdd) else print 0, and add check that if there are even number of odd numbers then nth number will be 0 regardless of the parity of j-m.

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

353291565

I am getting TLE , please help in problem D

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

Nice editorial for F.

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

In problem C, cnteven is for what??

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

What is the "A well-known method can be used to count the number of pairs of numbers in the array (i,j) for which gcd(ai,aj)=g for any number g from 1 to maxA" in F. Can someone say how I can google it or provide a link to editorial of this method?

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

    Well, I think I understood what method was mentioned here. In short, this is a regular dp, where we count the number of pairs that x divides, and then subtract all the other gcds that x divides. This can be done as in sieve of Eratosthenes, and it will work for O(nlogn)

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

Easy solution for D: Let's replace each edge v->u with an edge between two FAKE vertices: (v << 64 | Y) -> (u << 64 | X + Y), where X is the value associated with vertex v, and Y with u. This way, we obtain a new graph in which ANY path corresponds to a Fibonacci path! Simply count the number of paths in this graph using DFS and caching. https://mirror.codeforces.com/contest/2176/submission/353494951

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

Can you guys tell me why my D is TLEing?

#include <bits/stdc++.h>
using namespace std;

/* #define int long long */

const int MOD = 998244353;
int madd(int a, int b) {
    a %= MOD;
    b %= MOD;

    return (a + b) % MOD;
}

int32_t main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int tt;
    cin >> tt;

    while(tt--) {
        int n, m;
        cin >> n >> m;
        vector<long long> a(n);
        for(int i = 0; i < n; ++i) {
            cin >> a[i];
        }

        //dp[i] = number of fibonacci sequences ending in edge i inclusive
        vector<int> dp(m, 1);
        vector<pair<int, int>> e;

        auto cmp = [a](pair<int, int> pa, pair<int, int> pb) {
            return a[pa.second] < a[pb.second];
        };

        for(int i = 0; i < m; ++i) {
            int u, v;
            cin >> u >> v;

            u--;
            v--;
            e.push_back({u, v});
        }

        vector<map<int, long long>> buffer(n);

        sort(e.begin(), e.end(), cmp);

        for(int i = 0; i < m; ++i) {
            auto [u, v] = e[i];
            long long sum = a[u] + a[v];

            dp[i] = madd(dp[i], buffer[u][a[v]]);
            buffer[v][sum] = madd(buffer[v][sum], dp[i]);
        }

        int ans = 0;
        for(int x: dp) {
            ans = madd(ans, x);
        }
        cout << ans << '\n';
    }
}

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

PROBLEM D: I am getting TLE on test case 11 353509271. What can I do better?

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

For F, a slightly better bound on K can be given. The primorial function is bigger than n! so it's inverse is less. By Stirling, n! is $$$O\left(e^{n \ln(n)}\right)$$$ and the inverse of this is $$$O\left(\log(n)/\log(\log(n))\right)$$$

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

I've found, I guess, very simple linear solution to problem E.

Let's see that an element can be killed only by first not-less element on the right|left, or first not-less than first not-less on the right|left, or ...

We will denote the set of elements, which are able to kill element at position $$$i$$$, as $$$killers(i)$$$.

Let's assign for each $$$i$$$ the cheapest element from $$$killers(i)$$$ to kill $$$i$$$.

The observation: there is a sequence of deletions which satisfies our assignments.

The proof's sketch: Let's draw an arrow from each position i to his killer. It suffices to show that there are no crossing arrows. We can see that if two arrows are crossing, then we can reassign one of them and obtain cheaper solution.

It is known that we can compute "first not-less on right|left" in linear time. With a simple DP we can also compute those assignments in $$$O(n)$$$. The answer is just a sum of costs of killing each element. So we solved E without queries.

We can now observe that any changes in elements that doesn't belong to $$$killers(i)$$$ don't have any impact on the cost of killing $$$i$$$. Hence it suffices to compute, for each element, the first time that some member of $$$killers(i)$$$ is changed to zero. We can solve it in $$$O(n)$$$ with very similar DP.

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

I thought of a different solution for problem C .

The approach is to separate the numbers into even and odd and sort even numbers in descending order and odd numbers in descending order. If there are no odd numbers then the answer would be zero for all k. If there are no even numbers then the answer would be zero for even k and the largest odd number for odd k. We need the sum of even numbers to reduce the O(n) complexity to calculate again, so prefix sums of even numbers are used. For each k, first start by placing the largest odd number. If the number of evens available are enough then just add the number of even numbers required in descending order. If the number of even numbers available are less than required, then if the number of odd numbers to be used are even, simply place them before the largest odd number as their sum would give 0, so the answer should be the largest odd number plus the sum of all even numbers. If the number of odd numbers to be used are odd, then simply remove the smallest even number and place all odd numbers available before the largest odd number, and if k equals n (that is all numbers are to be used) then the sum would be 0.

Here is my submission :

https://mirror.codeforces.com/contest/2176/submission/356942161

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

Problem C. Odd Process

Can anybody explain sample cases 3 and 4?

Input:

5
4 1 3 1 2
5
4 2 3 1 3

Output:

3 7 9 7 9
3 7 9 7 9

In sample 3, for example, on $$$k=4$$$, doesn't the bag contain $$$[3, 4, 2, 1]$$$, with the even sum $$$10$$$, therefore being emptied and giving a score of $$$0$$$? How is the score $$$7$$$ instead? Same confusion with sample 4.

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

    For $$$k=4$$$ we can take $$$[1, 1, 3, 4]$$$ in this order. Maybe you miss that we can solve problem independently from previous $$$k$$$

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

      You are right. I missed the point that for each $$$k$$$ we begin with an empty bag. Thanks for the clarification.

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

4

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

A Better Approach for Problem C 2176C - ODD PROCESS - Odd Process LYC_666 ~~~~~ #include<bits/stdc++.h> using namespace std;

define int long long

bool cmp(int t1,int t2) { return t1 > t2; }

signed main() { ios::sync_with_stdio(0), cin.tie(0); int t; cin >> t; while (t--) { int n; cin >> n; vectorodd, even; for (int i = 0; i < n; i++) { int v; cin >> v; if (v % 2 == 0) { even.push_back(v); } else { odd.push_back(v); } } if (odd.empty()) { for (int i = 0; i < n; i++) { cout << "0 "; } cout << "\n"; continue; } sort(even.begin(), even.end(),cmp), sort(odd.begin(), odd.end(), cmp); int size = even.size() + 1; vectorpre(size + 1); pre[1] = odd[0]; for (int i = 0; i < even.size(); i++) { pre[i + 2] = pre[i + 1] + even[i]; } for (int i = 1; i < n; i++) { if (i <= size) { cout << pre[i]<<" "; } else { if ((i — size) % 2 == 1) { cout << pre[size — 1] << " "; } else { cout << pre[size] << " "; } } } if (odd.size() % 2 == 0) { cout << "0"; } else { cout << pre[size]; } cout << "\n"; } return 0; } ~~~~~