MXMODSUM - Editorial

the time complexity of your approach is O(n*n) so it will get TLE

1 Like

why we have calculate mod like this (((a[i]+m-a[n]%m)%m;)) ??
can’t we simply write ((a[i]+a[n] - (a[n])-a[i])%m)) ?

1 Like

can you please tell me why only some of the mod variables(mod1,mod2,mod3,mod4) getting calculated? when i tried debugging , i noticed that only 1 or 2 of those lines are getting calculated in my code.

#include"bits/stdc++.h"
#define ll long long int
#define MOD 1000000007
using namespace std;


ll findMod(vector<ll> &arr,ll i,ll j,ll m)
{
    if(arr[i]-arr[j]>=0)
    {
        return (arr[i]+arr[j]+  ((arr[i]-arr[j])%m));
    }


    ll thirdTerm;
    if(abs(arr[i]-arr[j])%m==0)
      thirdTerm=0;
    else
      thirdTerm= arr[i]-arr[j]+ m*( (abs(arr[i]-arr[j])/m)+1);

    return (arr[i]+arr[j] + thirdTerm);
}

int main()
{
     ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    ll t;
    cin>>t;
    while(t--)
    {
        ll n,m;
        cin>>n>>m;
        vector<ll> arr(n);
        for(ll i=0;i<n;i++)
        {
            cin>>arr[i];
        }

        sort(arr.begin(),arr.end());

        
        ll mod1=findMod(arr,n-2,n-1,m);
        ll mod2=findMod(arr,n-1,n-2,m);
        ll mod3=findMod(arr,n-1,0ll,m);
        ll mod4=findMod(arr,0ll,n-1,m);


        cout<<max(mod1,max(mod2,max(mod3,mod4)))<<endl;

    }
    return 0;
}

Write my thoughts here.
(I think this is the simplest way of thinking)

  • Aj + ((Ai - Aj) mod M)

Let’s increase Aj by 1.

  • (left side) : always +1
  • (right side) : -1 or +(M-1) (when Ai=Aj mod M)

By considering the left side and the right side together,
you can see that there is no loss in increasing Aj.
(Because the change is always 0 or +M)

Therefore, it is best to use Amax for Aj.

1 Like

issue with mod calculation:
lets say you have a[i]=3,a[j]=7 and m=9;
then there are two possible cases:
(3-7)%9 =5 and (7-3)%9=4

so one of the mod value is greater than other(may be equal)
your mod calculation works wrongly when a[i]<a[j]

1 Like

Why the test case as following:

N=4 M=18
A=[3, 3, 3, 3]

not included
some solutions have passed not considering the above mentioned test case

for example, this solution:
https://www.codechef.com/viewsolution/64900842

3 Likes

Weak test case

Track only the biggest and second biggest numbers. Even a sorting is not needed.

It passes, but should not: CodeChef: Practical coding for everyone
Correct implementation: CodeChef: Practical coding for everyone

Your code fails for the test case mentioned by @aryan_sinha .

2 Likes

Oh, thanks for pointing it out. I have updated the comment

Yeah not needed

why it is partially accept

can someone tell me what is wrong with it

#include <bits/stdc++.h>

using namespace std;

int main() {
// your code goes here
int tt;
cin>>tt;
int maxi=0;
while(tt–){
int n,m;
cin>>n>>m;

    if(m>=1000 && m<=2){
        continue;
    }
    
    int arr[n];
    maxi=0;
    
    for(int i=0;i<n;i++){
        cin>>arr[i];
    }
    
    for(int i=0;i<n;i++){
        int first=arr[i];
        for(int j=0;j<n;j++){
            int second=arr[j];
            int mod= ((first % m) - (second % m) + m)% m;
            int mini=first+second+mod;
            
            
            maxi=max(maxi,mini);
        }
    }
    cout<<maxi<<endl;
    
}

return 0;

}

1 Like
import java.util.*;
import java.lang.*;
import java.io.*;

/* Name of the class has to be "Main" only if the class is public. */
class Codechef
{
	public static void main (String[] args) throws java.lang.Exception
	{
		// your code goes here
		Scanner sc = new Scanner (System.in);
		int t = sc.nextInt();
		while(t!=0){
		    int n = sc.nextInt();
		    int m = sc.nextInt();
		    int [] a = new int [n];
		    for(int i=0;i<n;i++){
		        a[i] = sc.nextInt();
		    }
		    int def=0,sum=0, max=0;
		    for(int i=0;i< n -1;i++){
		        def =a[i] - a[n-1];
		        if( def < 0) def = m - ((a[n-1] - a[i]) % m );
		        else def = (a[i] - a[n-1]) % m;
		        sum =a[i] + a[n-1] +  def;
		        if(sum>max) max = sum;
		    }
		    System.out.println(max);
		    t--;
		}
	}
}

This gave me the output but the test cases failed …

I have the same doubt.

for (int a: arr) {
		        int term = a + a[n-1] + (a - a[n-1]) % m;
		        maxVal = Math.max(maxVal , term);
		    }

Why does the above approach not work, but the lower one does? Is this related to distributive property of modulo in some way? Please advise me on this.

for (int a: arr) {
		        int term = a +  a[n-1] + ((a - a[n-1] ) % m + m) % m;
		        maxVal = Math.max(maxVal , term);
		    }
1 Like

For some languages, a % m can be negative if a is negative. That’s why you need to fix it (by adding m back to make it positive before modding again).

3 Likes

Update the time complexity, its not linear

@demystify can you help please.
been stuck here from yesterday.

The editorial explanation and the Preparer’s Solution are both linear.

I’m sorry but I could not understand your question. However, I have a few comments that may help you.

What editorial is saying is "When A_i is fixed, it is always optimal to choose A_{max} as A_j". In other words, “If you brute-force A_i for A_j = A_{max}, you will find the optimal solution.”

It is not enough to search only some A_i; you must try all possibilities as A_i.

By the way,

    ll thirdTerm;
    if(abs(arr[i]-arr[j])%m==0)
      thirdTerm=0;
    else
      thirdTerm= arr[i]-arr[j]+ m*( (abs(arr[i]-arr[j])/m)+1);

this code is very technical and probably correct. But writing ((a[i] - a[j]) % m + m) % m is the simplest and recommended.

1 Like

Here is another solution.
I used this solution during the contest. Many others may have used this solution.

Let’s use the “division into cases” and “variable separation” techniques to remove the \mathrm{mod}.
This idea can be also applied to \mathrm{abs}(a - b), \min(a, b), \max(a, b), etc. In my experience, I often use this technique to remove \mathrm{abs}.

Before “division into cases”, pre-calculate m[i] = A[i] \, \% \, M. Let us also define f(i,j) = A[i] + A[j] + ((A[i] - A[j]) \mod M) = A[i] + A[j] + ((m[i] - m[j]) \mod M).

  • Case 1: m[i] = m[j]

    • f(i,j) = A[i] + A[j]
  • Case 2: m[i] > m[j]

    • f(i,j) = (A[i] + m[i]) + (A[j] - m[j])
  • Case 3: m[i] < m[j]

    • f(i,j) = (A[i] + m[i]) + (A[j] - m[j]) + M

Let us consider Case 2. For any i, we can write

  • \max_{j} \{ f(i,j) \, | \, m[i] > m[j] \} = (A[i] + m[i]) + \max_{j} \{ A[j] - m[j] \, | \, m[i] > m[j] \}.

Since \max_{j} \{ A[j] - m[j] \, | \, m[i] > m[j] \} can be managed by priority_queue etc., the optimal solution of Case 2 can be obtained by processing in ascending order of m[i]. The total complexity is O(N \log N). The same is true for Case 3.

In implementation, after processing Case 1, make m[i] unique before processing Case 2 and Case 3 (leaving the larger A[i] as the tiebreaker for m[i]).

Here is my code (sorry for the mess…).
https://www.codechef.com/viewsolution/64893142