cppAcademy
FROM LEARNING TO COMPETING

Expert.
Put your skills to the test.

Bulgarian Informatics Group A · 2007–2026

274 independently explained problems: 54 Municipal, 54 Regional, 109 National Olympiad and 57 Autumn Tournament tasks. Difficulty labels are learning estimates, not official ratings. Some events share Senior/IATI or Group A/B problem sets. Special formats, scoring limitations and source clarifications are explained on affected tasks. Existing shared National-round problems keep their permanent URLs.
GROUP A2008 · HardGaussian elimination over a finite field

Invert a Ternary Neighbour-Sum Grid

Autumn Tournament (2008)

Submission name: table.cpp

Problem summary

A grid S has entries0,1,2. T[i][j] is the sum modulo3 of S at its orthogonal neighbours. Given T, count all possible S modulo333333. Cells outside the grid contribute0.

Input

m n, then the m by n grid T.

Output

The number of compatible grids, modulo333333.

Constraints

2≤m,n≤32.

Worked example

Original statement sample.

Input

3 4
0 2 2 1
1 0 2 2
1 1 0 2

Output

1

Solution analysis

  1. Choosing the first row of S determines every later row. If the row above and the current row are known, rearrange the neighbour equation to obtain S[i+1][j]=T[i][j]−S[i−1][j]−S[i][j−1]−S[i][j+1] modulo3.
  2. Treat the n first-row cells as variables. Carry each derived cell as an affine expression with n coefficients and a constant. Propagate through all m rows. The extra row m+1 must be zero, leaving n linear equations in n unknowns. Solve those equations over the field modulo3, not modulo333333.
  3. For the sample, write the first row as x1,x2,x3,x4. The next row starts with −x2 and2−x1−x3. Continuing propagation and imposing the zero bottom row gives rank4, so the four first-row values are uniquely determined and the answer is1. In general, an inconsistent system contributes0; otherwise each free variable has three choices.

Why it works

The recurrence is a rearrangement of exactly one cell equation, so it uniquely constructs all remaining rows from the first row. All equations except the bottom boundary are enforced during construction. The final linear system enforces that boundary too, establishing a bijection between its solutions and valid grids. A consistent rank-r system over F3 has3^(n−r) solutions.

Complexity: O(mn²+n³) time and O(n²) auxiliary space. Each propagated cell carries n+1 coefficients, and Gaussian elimination operates on an n by(n+1) matrix.

Watch out. Do not eliminate modulo333333: it is not a field. Equations use modulo3; only the final count uses333333. Include absent left/right/top/bottom neighbours as zero and normalize negative remainders.

Commented C++17 solution

An independently written complete program with standard headers.

#include<algorithm>
#include<iostream>
#include<vector>
using namespace std;
int mod3(int value){
    value%=3;
    if(value<0){
        value+=3;
    }
    return value;
}
int main(){
    int rows,columns;
    cin>>rows>>columns;
    vector<vector<int>>target(rows,vector<int>(columns));
    for(auto&row:target){
        for(int&value:row){
            cin>>value;
        }
    }
    using Row=vector<vector<int>>;
    Row above(columns,vector<int>(columns+1,0));
    Row current=above;
    for(int j=0;j<columns;j++){
        current[j][j]=1;
    }
    for(int i=0;i<rows;i++){
        Row below(columns,vector<int>(columns+1,0));
        for(int j=0;j<columns;j++){
            for(int coefficient=0;coefficient<=columns;coefficient++){
                int value=-above[j][coefficient];
                if(j>0){
                    value-=current[j-1][coefficient];
                }
                if(j+1<columns){
                    value-=current[j+1][coefficient];
                }
                if(coefficient==columns){
                    value+=target[i][j];
                }
                below[j][coefficient]=mod3(value);
            }
        }
        above.swap(current);
        current.swap(below);
    }
    // The propagated extra row must equal zero.
    for(auto&equation:current){
        equation[columns]=mod3(-equation[columns]);
    }
    int rank=0;
    for(int column=0;column<columns;column++){
        int pivot=rank;
        while(pivot<columns&&current[pivot][column]==0){
            pivot++;
        }
        if(pivot==columns){
            continue;
        }
        swap(current[pivot],current[rank]);
        int inverse=current[rank][column];
        for(int j=column;j<=columns;j++){
            current[rank][j]=mod3(current[rank][j]*inverse);
        }
        for(int row=rank+1;row<columns;row++){
            int factor=current[row][column];
            for(int j=column;j<=columns;j++){
                current[row][j]=mod3(current[row][j]-factor*current[rank][j]);
            }
        }
        rank++;
    }
    for(int row=rank;row<columns;row++){
        if(current[row][columns]!=0){
            cout<<0<<'\n';
            return 0;
        }
    }
    int answer=1;
    for(int freeVariable=rank;freeVariable<columns;freeVariable++){
        answer=answer*3%333333;
    }
    cout<<answer<<'\n';
}

Source: Arena Olimpiici ↗