CHKPTS - Editorial

Let a = x-y
b = (x%c + c)%c
Can we make key as a + b + a*b in hashmap ?
Someone please help me in finding bug. I haven’t found any yet
Link - CodeChef: Practical coding for everyone

Can anyone tell why i am getting TLE in this https://www.codechef.com/viewsolution/34620865.
I have the same logic as in editorial but getting TLE in python.

Same issue I am also facing I guess in python.
Check my sol : CodeChef: Practical coding for everyone

although I just realised that this has costed me 130+ points :slight_smile:
only because I choose Java and not C/C++ … this is life

It’s one of the most well-written editorials I have ever seen. Thank you @taran_1407 for the same.

@taran_1407 you explained the solution quite amazingly however during the contest instead of taking median of elements i was taking average so can you please tell me why would taking the average won’t work in this question please?

can you please share your code?

@supplexcity Sure. But sorry for ugly implementation. I wasn’t thinking straight during contest time. I added some comments though.

#pragma GCC optimize("Ofast")
#pragma GCC target("avx,avx2,fma")
#pragma GCC optimization ("unroll-loops")

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

typedef long long ll;

const int MX=500005;
vector <int> v[MX],u[MX];

// calculate the number of moves to move all points of k'th to p
ll cost(int k,ll c,ll p)
{
    int l=u[k].size();
    ll r=0;
    for(int i=0;i<l;i++) r+=abs((ll)u[k][i]-p)/c;
    return r;
}

// ternary search to find the minimum number of moves
ll f(int k,ll c)
{
    ll l=*min_element(begin(u[k]),end(u[k]));
    ll r=*max_element(begin(u[k]),end(u[k]));
    ll mn=LLONG_MAX;
    while(true){
        if(r-l<4ll*c){
            while(l<=r){
                ll cs=cost(k,c,l);
                mn=min(mn,cs);
                l+=c;
            }
            break;
        }
        ll m1=l+((r-l)/(c*3ll))*c;
        ll m2=r-((r-l)/(c*3ll))*c;
        ll cs1=cost(k,c,m1);
        ll cs2=cost(k,c,m2);
        if(cs1>cs2) l=m1;
        else r=m2;
    }
    return mn;
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        ll mv=0;
        int n,c,x,y,ans=0,k=0,cp=0;
        scanf("%d %d",&n,&c);
        map <int,int> mp;
        for(int i=0;i<n;i++){
            scanf("%d %d",&x,&y);

            // group by y-x
            int p=y-x;
            if(mp.find(p)==end(mp)){
                v[mp[p]=k++].push_back(x);
            }
            else{
                v[mp[p]].push_back(x);
            }
        }
        for(int i=0;i<k;i++){
            int l=v[i].size(),z=0;
            ll m=*min_element(begin(v[i]),end(v[i]));
            if(m<0) m=-m;
            else m=0;

            // group by mod c
            map <ll,int> mm;
            for(int j=0;j<l;j++){
                ll x=((ll)v[i][j]+m)%(ll)c;
                if(mm.find(x)==end(mm)){
                    u[mm[x]=z++].push_back(v[i][j]);
                }
                else{
                    u[mm[x]].push_back(v[i][j]);
                }
            }
            v[i].clear(),cp+=z;

            // sum up number of moves for all groups
            for(int j=0;j<z;j++){
                mv+=f(j,c);
                u[j].clear();
            }
        }
        printf("%d %lld\n",cp,mv);
    }
    return 0;
}
1 Like

@priyansh19077 Thank you:) I also got it after some time. I took this example:

c=3
numbers: 0,9,9

average = 6
number of moves=2+1+1=4

median = 9
number of moves=3+0+0=3 which is lesser.

Use Python. Brief and concise.

1 Like

Correct me if I’m wrong. Let’s say one point gives a = 2, b = 3, and another point give a = 3, b = 2. Now won’t you be storing them under the same group, when they are clearly a part of two different groups?

My approach was a little different than the ones I am seeing here. Still got accepted . Just sharing my approach. For any point (X,Y) , I found the point (A,B) such that B is either 0 or B is closest possible positive value it can take for the given C , i.e the point just above the X axis.
Now , it is clear that if 2 points gives same (A,B) , they can be converged into same points. So, simply the number of distinct checkpoints. Hence , number of Checkpoints needed is number of distinct (A,B).
Now, for number of Opeartions. Say (X1,Y1) ,(X2,Y2) … (Xk , Yk) have same (A,B). Then I can simply sort these K points and the checkpoint will have to me the (k/2)th point in the sorted list.
I simply found the sum of distance (either X or Y) of (K/2)th point from all points and number of operations = (Distance/C).
I did this for all possible (A,B) that was generated.
Proof : - If you have N points on a Line, then the sum of distance of a point from all other points is a decreasing function till (N/2) points and then an increasing fucntion. So, N/2 is the minima.

I also tried this
n = a+b
Key = (n*(n+1)) /2 + a
Can you provide me a case where this will fail

That is some brilliant hashing. I don’t think there will be collisions. Are you sure the rest of your algorithm is solid?

[UPD]: I tried the hash that you have specified with my (AC) algorithm and it gives a WA. The problem has to be the hash function. I was able to find a case with -ve b. I know b cannot be negative, but I’m sure we’ll be able to find a collision for a,b > 0.
Pair 1: a = 3, b = -2
Pair 2: a = 1, b = 1

In general, it’s always better to use the std hash to hash the pairs. This can be easily done by initializing your hashmap as unordered_map<pair<int, int>, typename>. This is always better than coming up with a custom hash for pairs :stuck_out_tongue: (especially in a short contest).

Select any. It wont matter.

Thanks a lot! I was facing the BUG1 really helped me debug really fast.

Can someone tell mistake in my code, it is almost same as in editorial

Please find my solution here:- My solution

PS: I even tried ((x % c) + c) % c) in map from editorial but still WA.

You need to find the minimum number of times that so that you move the checkpoints.

Consider this example in 1D plane 1 3 8 and let c be 1, here mean is 4 and the median is 3. If you move them to mean you will move all 3 to 4 and that gives me 3 + 1 + 4 but in case of median we have 2 + 0 + 5.

Yeah, I understood there must be some collision. Actually i write code in java so i have to write custom pair class to go to. I tried with custom pair class by manipulating hash and equals function and it got AC. Didn’t work out during contest. It’s good that i atleast learned something. Would be great if i could able to find the collision.

Oh! To tackle that maybe you can use a 2D map? Map<Integer, Map<Integer, ArrayList>> . I don’t know java, i’m just guessing.

1 Like