Soluție HackerRank pentru Cross Matrix, subdomeniul Algebra, în C++14. Include cerința formatată, exemple, explicația pașilor și cod sursă.

  • Problemă: Cross Matrix
  • Domeniu: Algebra
  • Limbaj: C++14

Challenge: Cross Matrix

Subdomeniu: Algebra (algebra)

Scor cont: 120.0 / 120

Submission status: Accepted

Submission score: 1.0

Submission ID: 464834972

Limbaj: cpp14

Link challenge: https://www.hackerrank.com/challenges/cross-matrix/problem

Cerință

You are given a *N* * *N* matrix, *U*. You have to choose 2 sub-matrices A and B made of only 1s of *U*, such that, they have at least 1 cell in common, and each matrix is not completely engulfed by the other, i.e.,

If *U* is of the form

![image-U](https://s3.amazonaws.com/hr-assets/0/1526566968-bc96620304-image-u.png)

and *A* is of the form

![image-A](https://s3.amazonaws.com/hr-assets/0/1526566750-388f1c7813-image-A.png)

and *B* is of the form

![image-B](https://s3.amazonaws.com/hr-assets/0/1526566997-2b849f77a5-image-B.png)

then, there exists atleast 1 a<sub>i, j</sub> : a<sub>i, j</sub> ∈ *A* and a<sub>i,j</sub> ∈ *B*
then, there exists atleast 1 a<sub>i1, j1</sub> : a<sub>i1, j1</sub> ∈ *A* and a<sub>i1,j1</sub> ∉ *B*
then, there exists atleast 1 a<sub>i2, j2</sub> : a<sub>i2, j2</sub> ∈ *B* and a<sub>i2,j2</sub> ∉ *A*
a<sub>x,y</sub> = 1 ∀ a<sub>x,y</sub> ∈ *A*
a<sub>x,y</sub> = 1 ∀ a<sub>x,y</sub> ∈ *B*

How many such (*A*, *B*) exist?

Input Format
The first line of the input contains a number *N*.
*N* lines follow, each line containing *N* integers (0/1) NOT separated by any space.

Output Format
Output the total number of such (A, B) pairs. If the answer is greater than or equal to 10<sup>9</sup> + 7,
then print answer modulo (%) 10<sup>9</sup> + 7.

Constraints

2 ≤ *N* ≤ 1500
a<sub>i,j</sub> ∈ [0, 1] : 0 ≤ i, j ≤ N - 1

Sample Input

4
0010
0001
1010
1110

Sample Output

10

Explanation

X means the common part of A and B.

We can swap A and B to get another answer.

0010
0001
A010
XB10

0010
0001
A010
XBB0

0010
0001
10A0
1BX0

0010
0001
10A0
BBX0

0010
0001
1010
AXB0

TimeLimits

Time limit for this challenge is mentioned [here](http://hr-testcases.s3.amazonaws.com/2492/timelimit.json)

Cod sursă

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

// Cross Matrix - HackerRank
// Count ordered pairs of overlapping all-ones submatrices such that neither contains the other.

static const int MOD = 1000000007;
static inline int addmod(int a,int b){ a+=b; if(a>=MOD) a-=MOD; return a; }
static inline int submod(int a,int b){ a-=b; if(a<0) a+=MOD; return a; }

static vector<int> genUBound(const vector<string>& mat){
    int n = (int)mat.size();
    vector<int> ub(n*n, 0);
    for(int i=0;i<n;i++){
        int rowOff = i*n;
        int prevOff = (i-1)*n;
        for(int j=0;j<n;j++){
            if(mat[i][j]=='1'){
                ub[rowOff + j] = (i==0 ? 1 : ub[prevOff + j] + 1);
            }
        }
    }
    return ub;
}

static void reverseEachRow(vector<int>& a, int n){
    for(int i=0;i<n;i++){
        auto it = a.begin() + i*n;
        reverse(it, it + n);
    }
}

static vector<int> genCounter(const vector<int>& ub, int n){
    vector<int> counter(n*n, 0);
    vector<int> left(n), st(n);

    for(int i=0;i<n;i++){
        int end = -1;
        int base = i*n;
        for(int j=0;j<n;j++){
            int h = ub[base + j];
            left[j] = j;
            while(end >= 0 && h <= ub[base + st[end]]){
                left[j] = left[st[end]];
                end--;
            }
            if(end==-1 || h != ub[base + st[end]]) st[++end] = j;

            long long val = 1LL*(j - left[j] + 1) * h;
            if(left[j] > 0) val += counter[base + left[j] - 1];
            counter[base + j] = (int)(val % MOD);
        }
    }
    return counter;
}

static vector<int> genSum(vector<int> counter, int n){
    for(int i=0;i<n;i++){
        int base = i*n;
        for(int j=1;j<n;j++){
            counter[base + j] = addmod(counter[base + j], counter[base + j - 1]);
        }
    }
    for(int i=1;i<n;i++){
        int base = i*n;
        int prev = (i-1)*n;
        for(int j=0;j<n;j++){
            counter[base + j] = addmod(counter[base + j], counter[prev + j]);
        }
    }
    return counter;
}

static long long comb3(long long t){
    if(t < 3) return 0;
    __int128 v = (__int128)t * (t-1) * (t-2);
    v /= 6;
    return (long long)(v % MOD);
}
static long long comb4(long long t){
    if(t < 4) return 0;
    __int128 v = (__int128)t * (t-1) * (t-2) * (t-3);
    v /= 24;
    return (long long)(v % MOD);
}

static int containPairs(const vector<int>& ub, int n){
    int H = n, W = n;
    vector<int> diff((H+1)*(W+1), 0); // can be negative

    vector<int> left(W+1), st(W+1);

    for(int i=0;i<n;i++){
        int end = -1;
        int base = i*n;
        for(int j=0;j<=n;j++){
            int cHeight = (j==n ? 0 : ub[base + j]);
            left[j] = j;

            while(end >= 0 && cHeight < ub[base + st[end]]){
                int height = ub[base + st[end]];
                left[j] = left[st[end]];
                int width = j - left[st[end]];
                end--;
                int mHeight = (end >= 0) ? max(cHeight, ub[base + st[end]]) : cHeight;

                diff[height*(W+1) + width] += 1;
                diff[mHeight*(W+1) + width] -= 1;
            }
            if(end == -1 || cHeight > ub[base + st[end]]){
                st[++end] = j;
            }
        }
    }

    int maxDim = n + 5;
    vector<long long> cm3(maxDim+1, 0), cm4(maxDim+1, 0);
    for(int i=0;i<=maxDim;i++){
        cm3[i] = comb3(i);
        cm4[i] = comb4(i);
    }

    long long total = 0;
    for(int h=1; h<=H; h++){
        for(int w=1; w<=W; w++){
            int v = diff[h*(W+1) + w];
            if(v==0) continue;
            long long term = cm3[h+2] * cm4[w+3] % MOD;
            total = (total + term * (long long)v) % MOD;
        }
    }
    if(total < 0) total += MOD;
    return (int)total;
}

static int solveCrossMatrix(vector<string> mat){
    int n = (int)mat.size();
    const int inv2 = (MOD + 1) / 2;

    // original
    vector<int> ub = genUBound(mat);
    vector<int> counter = genCounter(ub, n);
    int contain = containPairs(ub, n);

    // mirrored (to count bottom-left)
    reverseEachRow(ub, n);
    vector<int> counterRev = genCounter(ub, n);

    // vertical flip for top-corner related counting
    reverse(mat.begin(), mat.end());
    vector<int> ubRev = genUBound(mat);
    vector<int> sumRev = genSum(genCounter(ubRev, n), n);

    // also horizontal flip => rotation 180 => top-left related
    reverseEachRow(ubRev, n);
    vector<int> sum = genSum(genCounter(ubRev, n), n);

    int total = sum[n*n - 1]; // total #submatrices of ones (mod)

    contain = submod(contain, total); // remove (R,R)

    long long deviation = 0;

    // count disjoint unordered pairs (with diagonal double-count)
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            int down = (n - i - 2 >= 0) ? sum[(n - i - 2)*n + (n - 1)] : 0;
            int right = (n - j - 2 >= 0) ? sum[(n - 1)*n + (n - j - 2)] : 0;
            int rightDown = (n - i - 2 >= 0 && n - j - 2 >= 0) ? sum[(n - i - 2)*n + (n - j - 2)] : 0;

            int other = right;
            other = addmod(other, down);
            other = submod(other, rightDown);

            deviation = (deviation + 1LL * counter[i*n + j] * other) % MOD;
        }
    }

    // subtract diagonal cases counted twice
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            int c = counterRev[i*n + j];
            if(c==0) continue;
            if(n - i - 2 < 0 || n - j - 2 < 0) continue;
            int leftUp = sumRev[(n - i - 2)*n + (n - j - 2)];
            deviation = (deviation - 1LL * c * leftUp) % MOD;
        }
    }
    if(deviation < 0) deviation += MOD;

    long long res = 1LL * total * (total - 1) % MOD * inv2 % MOD; // unordered pairs
    res = (res - contain - deviation) % MOD;
    if(res < 0) res += MOD;

    res = res * 2 % MOD; // ordered
    return (int)res;
}

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

    int n;
    cin >> n;
    vector<string> mat(n);
    for(int i=0;i<n;i++) cin >> mat[i];

    cout << solveCrossMatrix(mat) << "\n";
    return 0;
}
HackerRank Algebra – Cross Matrix