(Analysis by Benjamin Qi, C++ code by Alex Liang)

Subtask:

There are $2^N$ possible boards. For each board, we can iterate over all $K$ mooves, check the total number of points scored, and possibly update the best score seen so far.

The time complexity is $O(K2^N)$. Using bitmasks can help shorten the implementation.

#include <bits/stdc++.h>
using namespace std; 
 
int main(){
    int n, k;
    cin >> n >> k;
 
    vector<array<int, 3>> A(k);
    for (auto &[x, y, z] : A) {
        cin >> x >> y >> z;
        x--; y--; z--;
    }
    
    int bestVal = 0;
    int bestCount = 0;
 
    for (int msk = 0; msk < (1 << n); msk++) {
        int val = 0;
        for (auto [x, y, z] : A) 
            val += ((bool)((1 << x) & msk)) && !((bool)((1 << y) & msk)) && !((bool)((1 << z) & msk));
 
        if (val > bestVal) {
            bestVal = val;
            bestCount = 1;
        }
        else if (val == bestVal)
            bestCount++;
    }
    cout << bestVal << " " << bestCount << "\n";
}

Full Solution 1:

Observe that there are at most $N^3/2$ possible distinct mooves ($N$ choices for each of $x$, $y$, $z$, and we can assume $y<z$ without loss of generality). So instead of maintaining a list of all $K$ mooves we can instead store for each distinct moove how many times it appears in the input in an $N\times N\times N$ array. Then for each board, we can iterate over all distinct mooves that contribute to its score and sum their counts.

The time complexity is $O(N^32^N)$ with a good constant factor. Implementations with poor constant factors should still receive significant partial credit.

#include <bits/stdc++.h>
using namespace std; 
 
int main(){
    int n, k;
    cin >> n >> k;
 
    vector<vector<vector<int>>> isAt(n, vector<vector<int>>(n, vector<int>(n, 0)));
 
    for (int i = 0; i < k; i++) {
        int x, y, z;
        cin >> x >> y >> z;
        x--; y--; z--;
        isAt[x][min(y, z)][max(y, z)]++;
    }
 
    vector<int> score((1 << n), 0);
 
    for (int msk = 1; msk < (1 << n); msk++) {
        vector<int> mpos, opos;
 
        for (int i = 0; i < n; i++) {
            if ((1 << i) & msk)
                mpos.push_back(i);
            else
                opos.push_back(i);
        }
        for (int m : mpos)
            for (int i = 0; i < opos.size(); i++)
                for (int j = i + 1; j < opos.size(); j++)
                    score[msk] += isAt[m][opos[i]][opos[j]];
    }
    int bestVal = *max_element(score.begin(), score.end());
    int bestCount = count(score.begin(), score.end(), bestVal);
 
    cout << bestVal << " " << bestCount << "\n";
}

Full Solution 2:

Optionally, we can solve the problem in $O(N^22^N)$ time by reusing information across different boards instead of calculating their scores independently. In particular, if we know the score of a board and want to recalculate it after flipping one O to an M, this can be achieved in $O(N^2)$ time since there are only $O(N^2)$ distinct moos whose contributions to the score change. However, this doesn't end up being much faster than the previous solution.

#include <bits/stdc++.h>
using namespace std; 
 
int main(){
    int n, k;
    cin >> n >> k;
 
    vector<vector<vector<int>>> isAt(n, vector<vector<int>>(n, vector<int>(n, 0)));
 
    for (int i = 0; i < k; i++) {
        int x, y, z;
        cin >> x >> y >> z;
        x--; y--; z--;
        isAt[x][y][z]++;
    }
 
    vector<int> score((1 << n), 0);
 
    for (int msk = 1; msk < (1 << n); msk++) {
        int msb = 31 - __builtin_clz(msk);
        vector<int> mpos, opos;
 
        for (int i = 0; i < n; i++) {
            if ((1 << i) & msk)
                mpos.push_back(i);
            else
                opos.push_back(i);
        }
 
        // Previously
        score[msk] = score[msk ^ (1 << msb)];
 
        // Turned bad from flipping MSB
        for (int m : mpos) 
            for (int o : opos)
                score[msk] -= isAt[m][msb][o] + isAt[m][o][msb];
        
        // Turned good from flipping MSB
        for (int o1 : opos)
            for (int o2 : opos)
                score[msk] += isAt[msb][o1][o2];
    }
    int bestVal = *max_element(score.begin(), score.end());
    int bestCount = count(score.begin(), score.end(), bestVal);
 
    cout << bestVal << " " << bestCount << "\n";
}