GOODMATRIX - Editorial

PROBLEM LINK:

Practice
Contest: Division 1
Contest: Division 2
Contest: Division 3
Contest: Division 4

Author: sai1707
Tester: sushil2006
Editorialist: iceknight1093

DIFFICULTY:

Simple

PREREQUISITES:

None

PROBLEM:

An N\times M grid A is called best if it satisfies the following conditions:

  • Adjacent elements differ by exactly 1.
  • 2A_{x, y} = A_{x-1, y} + A_{x+1, y} whenever all three cells are valid.
  • 2A_{x, y} = A_{x, y-1} + A_{x, y+1} whenever all three cells are valid.

Given a grid A, find the minimum number of changes needed to make it the best.

EXPLANATION:

The conditions on a grid being best are fairly strong, so let’s try to understand what they actually mean.

Let’s look at the condition on three consecutive elements within a row, i.e. 2\cdot A_{x, y} = A_{x, y-1} + A_{x, y+1}.
If we rearrange this expression a bit, it becomes A_{x, y} - A_{x, y-1} = A_{x, y+1} - A_{x, y}.

In other words, differences between adjacent elements (when going from left to right) must be equal within a row.
Essentially, each row must look like either
x, x+1, x+2, x+3, \ldots or x, x-1, x-2, \ldots

Of course, the exact same applies to each column as well - all adjacent differences must be the same.

So, functionally, we’re just assigning each row and each column a difference of either +1 or -1, and this along with knowing A_{1, 1} will let us know all elements.
In fact, this can be strengthened even further: all row differences must be equal to each other — that is, either every row has a difference of +1, or every row has a difference of -1.

Proof

Suppose there are rows with different differences.
Then, some two adjacent rows, say i and i+1, must have different differences.
Without loss of generality, let’s say that row i has a difference of 1, and row i+1 has a difference of -1.

We need to look at a couple of cases now.
First, suppose M \geq 3, i.e. there are at least three columns.
Here, we look at the first three elements of each row.
In row i, suppose they’re x, x+1, x+2; while in row i+1 they’re y, y-1, y-2.
Then,

  • |x-y| = 1 should hold, since x and y are adjacent.
    So, either x-y = 1 or x-y = -1.
  • |(x+2) - (y-2)| = 1 should hold, since x+2 and y-2 are adjacent.
    This means |x-y+4| = 1, which says either x-y = -5 or x-y = -3.

In either case, we obtain a contradiction, so adjacent rows cannot have different differences.

Finally, consider M \lt 3.
If M = 1 then every row is a single element so there’s no row difference at all; this case can be ignored.
So, we need to deal with M = 2.

Here, note that the problem constraints guarantee that \max(N, M) \geq 3; so N \geq 3 must hold.
This means that there must either be a row above the i-th one, or a row below the (i+1)-th one.
W.l.o.g. let the row i+2 exist.

Now,

  • Row i must be [x, x+1], and row i+1 must be [y, y-1].
    The only way to satisfy the adjacent difference condition is for y = x+1, so that row i+2 is [x+1, x].
  • Now, let’s look at row i+2.
    To satisfy the column condition, its first element must be x+2 and its second element must be x-1.
    However, these don’t have a difference of 1, which is a contradiction!

This proves that all the rows must have the same difference, i.e. all +1 or all -1.

This of course applies to the column differences as well.
Note that the common row difference need not be equal to the common column difference.


Now, let’s see what this means for the grid itself.
As noted earlier, if A_{1, 1} is known, and all the row/column differences are known, the entire grid will be known.
However, row/column differences only have two options each, being \pm 1.

Observe that, if the row difference is fixed to be d_r and the column difference is d_c, then for any cell (i, j) we must have
A_{i, j} = A_{1, 1} + d_r\cdot (i-1) + d_c\cdot (j-1).

So, for a fixed choice of differences (d_r, d_c), each cell (i, j) has a unique value of A_{1, 1} for which it doesn’t need to be changed (that being A_{i, j} - d_r\cdot (i-1) - d_c\cdot (j-1), of course); whereas for every other A_{1, 1} it will need to be changed.
Let \text{freq}[x] denote the number of cells that are valid for A_{1, 1} = x. This is the number of cells that don’t need to change, if we set A_{1, 1} = x.
Thus, the minimum number of changes is simply N\times M minus the maximum frequency.

There are only four choices of (d_r, d_c), so we can simply try all of them, compute the minimum number of changes for each, and take the best of the four answers.

TIME COMPLEXITY:

\mathcal{O}(NM\log{NM}) per testcase.

CODE:

Editorialist's code (PyPy3)
import collections
for _ in range(int(input())):
    n, m = map(int, input().split())
    a = [ list(map(int, input().split())) for _ in range(n) ]
    
    ans = 0
    for dr in [-1, 1]:
        for dc in [-1, 1]:
            freq = collections.defaultdict(int)
            for i in range(n):
                for j in range(m):
                    freq[a[i][j] + dr*i + dc*j] += 1
            ans = max(ans, max(freq.values()))
    print(n*m - ans)
Tester's code (C++)
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

template<typename T> using Tree = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
typedef long long int ll;
typedef long double ld;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

#define fastio ios_base::sync_with_stdio(false); cin.tie(NULL)
#define pb push_back
#define endl '\n'
#define sz(a) (int)a.size()
#define setbits(x) __builtin_popcountll(x)
#define ff first
#define ss second
#define conts continue
#define ceil2(x,y) ((x+y-1)/(y))
#define all(a) a.begin(), a.end()
#define rall(a) a.rbegin(), a.rend()
#define yes cout << "Yes" << endl
#define no cout << "No" << endl

#define rep(i,n) for(int i = 0; i < n; ++i)
#define rep1(i,n) for(int i = 1; i <= n; ++i)
#define rev(i,s,e) for(int i = s; i >= e; --i)
#define trav(i,a) for(auto &i : a)

template<typename T>
void amin(T &a, T b) {
    a = min(a,b);
}

template<typename T>
void amax(T &a, T b) {
    a = max(a,b);
}

#ifdef LOCAL
#include "debug.h"
#else
#define debug(...) 42
#endif

/*



*/

const int MOD = 1e9 + 7;
const int N = 1e5 + 5;
const int inf1 = int(1e9) + 5;
const ll inf2 = ll(1e18) + 5;

void solve(int test_case){
    ll n,m; cin >> n >> m;
    ll a[n+5][m+5];
    rep1(i,n) rep1(j,m) cin >> a[i][j];

    ll ans = 0;
    for(auto x : {-1,1}){
        for(auto y : {-1,1}){
            map<ll,ll> mp;
            rep1(i,n){
                rep1(j,m){
                    ll add = (i-1)*x+(j-1)*y;
                    mp[a[i][j]-add]++;
                }
            }

            for(auto [x,c] : mp){
                amax(ans,c);
            }
        }
    }

    ans = n*m-ans;
    cout << ans << endl;
}

int main()
{
    fastio;

    int t = 1;
    cin >> t;

    rep1(i, t) {
        solve(i);
    }

    return 0;
}
1 Like

Why row and column difference should be either +1 or -1 ?
In the following case

2 4 6 8
4 6 8 10
6 8 10 12

its a good matrix but the row and column difference is not 1 or -1 .

Is there anything I missed in editorial ?

UPD : I missed the first condition , damm I am frustrated now .
Thanks @superbrainy007

1 Like

you missed the very first condition mentioned in the question, that is the absolute difference between any two adjacent elements is one

2 Likes

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

void helper(vector<vector>& v){
int n=v.size();
int m=v[0].size();
long long ans=0;

map<int,int> mp,mp2,mp3,mp4;

for(int i=0;i<n;i++){
    for(int j=0;j<m;j++){
        if(v[i][j]-j-i>0){
            mp[v[i][j]-j-i]++;
        }
        if(v[i][j]-j+i>0){
            mp2[v[i][j]-j+i]++;
        }
        
        if(v[i][j]+j-i>0){
            mp3[v[i][j]+j-i]++;
        }
        
        if(v[i][j]+j+i>0){
            mp4[v[i][j]+j+i]++;
        }
       
    }
   // cout<<endl;
}

int maxi=0,start,maxi2=0,start2,maxi3=0,start3,maxi4=0,start4;
for(auto i:mp){
  if(i.second>maxi){
    start=i.first;
    maxi=i.second;
  }
}

for(auto i:mp2){
  if(i.second>maxi2){
    start2=i.first;
    maxi2=i.second;
  }
}


for(auto i:mp3){
  if(i.second>maxi3){
    start3=i.first;
    maxi3=i.second;
  }
}


for(auto i:mp4){
  if(i.second>maxi4){
    start4=i.first;
    maxi4=i.second;
  }
}




maxi=max(maxi,max(maxi2,max(maxi3,maxi4)));

ans=n*m -maxi;



// for(int i=0;i<n;i++){
//     cout<<ans[i]<<" ";
// }



cout<<ans<<endl;

}

int main() {
int t;
cin>>t;
while(t–){
int n,m;
cin>>n>>m;
vector<vector> v(n);
// vector temp(n);

    for(int i=0;i<n;i++){
        vector<int> temp(m);
        for(int j=0;j<m;j++){
            cin>>temp[j];
        }
        v[i]=temp;
    }
    
    helper(v);
    
}

}

my code does exactly what said in the editorial , still it is giiving wrong answer , can someone tell me what is wrong with my code

Will this solution work for all types of input?
For example, consider an input like:
1 10 11
5 6 7

Wouldn’t it incorrectly return 5 as the answer by fixing on A11, while the correct answer is actually 3?
Did I overlook something?

By the way, I solved this problem using an O(N Ă— M Ă— N Ă— M) approach, and it got accepted!

In the following case

5 2 3
2 3 4

it required only one change at A11 to be a good matrix but if we look at the editorial solution it will produce a answer of 5 which looks wrong as per my understanding of the question. Can anyone explain me if i interpret the question incorrectly

But What all values can A1,1 = x take , how to find those potential values ?

You Shouldn’t be confused with Aij >= 1 , it is the array in the question that will have this condition but when i have to change elements , i can make a11 as 0 in this case and the array is a best array now
0 1 2

I was stuck in this part for almost a hour… turns out you don’t indeed need the first value at all , when you consider the first element as X , you can uniquely determine all the remaining array in terms of this X , so all you need to find is how many MAXIMUM elements can satisfy corresponding to a X , for example consider the simplest way to arrange these elements ( there would be 4 of such arrangements btw)
1 2 3 4
2 3 4 5
3 4 5 6
4 5 6 7
so you dont need 1 to be known at all , see in this type of arrangement , a[i][j] = i + j + k , where k is the top left element of the array(in this case its 1) , but if i take a map and increment the count of all such elements
freq[a[i][j] - i - j]++ , you will infact see it doesnt matter if i write -k inside the freq expression or not , I mean you can write freq[a[i][j] - i - j - k] as well , but it wont matter because all elements would have a -k in them and it wont affect our max frequency at all. Similarly there would be 3 more such arrangements , create 3 more maps and store the maximum across all the frequency arrays , and answer simply would be n * m - maxi.
For further clarification you can refer to my code.

Nope , The Editorial never mentions changing the 1st element at all. What you essentially are doing is considering the first element to be some random element(x) and then finding out how many elements in this array would comply with the top left element being x , what does that mean ??
So essentially there are 4 arrangements as the editorial mentions corresponding to 4 choices of choosing (dr , dc).
In the test case you have mentioned , consider the case of dr = 1 and dc = 1
so now you will take a map and increase the frequency ,
++freq[a[i][j] - i - j]
Now you’ll see that whatever be the top left element of this array it doesn’t matter. Like essentially you should be writing ++freq[a[i][j] - i - j - X] (where X is the top most element) but across the entire array X gets subtracted each time from any element so it DOESN’T AFFECT THE ANSWER AT ALL. Now when you closely observe this a[i][j] - i - j , you would be able to understand how the editorial smartly determines which first element would give us the maximum number of elements that do not need to be changed if we consider some top left element.
You can refer to my submission for more clarity.

Ok So , again i would get trolled if I say something like there’s just no way that 1144 people actually came up with a solution of such a moderately difficult problem. At this point it’s just about whose cheating source is good at coding and not who himself is good at coding. The increasing cheating cases is actually causing a lot of trouble to a genuine rated guy (like me). When you find out that from all the guys who have performed better than you , more than half of them are 3* , its disappointing. And IT’S CLEAR THAT THEY ARE CHEATING (except few ofc). I mean one of the guys asking a doubt for this problem in the comment section (I won’t mention the name) has already submitted the problem in the actual contest at 1.03 and has a better rank than me. Still the doubt he has asked seems to be so silly that he didn’t even understand the problem on the first hand. I would like some higher authority ( some guy who looks after all this and is reading this comment to please take some action , a reply to this comment would be appreciated as well ). And again this guy is just one of them , wait until you find out the actual number some day…

@dhiva_07 It’s obvious so many use AI to cheat and solve the question. I suppose around half of the participants are doing this. A problem of this difficulty won’t be solved by >500 people 4 years ago. But you should not worry; you should only care about your progress, and if you can solve some new questions, learn some new things and solve some stuff you wouldn’t have been able to in the past, you ARE improving, even if your rating compared to others doesn’t. Cheaters will get a better rank, but they are cheating themselves by doing so. They are not as good as their rank, and they know it

3 Likes

I completely understand your point and appreciate it as well , although I would want to be a 5* so bad as well , i was so close(1944) and then started to fall drastically , i guess the emotions came out a bit wrongly , You are indeed correct , in the end nothing can be done and we have to move on.

1 Like

Thanks bro your explanation made me clear my doubt . Also really liked this problem although wasn’t able to solve it in contest : )

1 Like