Official

E - Red Polyomino Editorial by en_translator


The number of choices of \(K\) squares out of \(N^2\) squares is \(_{N^2}C_{K}\), and \(_{64}C_{8} =4426165368 \gt 4 \times 10^9\), so a naive brute force won’t fit in time.
However, since the red squares are mutually connected, we can predict that there are fairly small number of combinations that satisfies the conditions. We may evaluate its upper bound in some mathematical way, but this time we can estimate it from the Sample Code \(3\).
Therefore, it is sufficient to perform a DFS (Depth-First Search) that enumerates the patterns in which the red squares are connected.
If you find it difficult to implement DFS, please refer to the following example as well.

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll>l_l;

set<vector<string>>used;//boards already searched
vector<string>s;//current board
ll answer=0;//resulting answer
ll n;
vector<ll> dx={1,0,-1,0};
vector<ll> dy={0,1,0,-1};

bool valid(ll x,ll y){
    return 0<=x && x<=n-1 && 0<=y && y<=n-1;//If (x,y) is in the board
}

void dfs(ll num){
    //num: how many red squares do we have to place?

    if(used.find(s)!=used.end()){
        return;//We've already searched this, skipping
    }
    used.insert(s);//Add the current board to the set of already-searched boards

    if(num==0){
        answer++;//This board satisfies the condition; add 1 to answer
        return; //We don't place red squares anymore
    }

    vector<l_l>next;//candidates of squares to place a red square next

    for(int i=0;i<=n-1;i++){
        for(int j=0;j<=n-1;j++){
            //We can put a new red square to (i, j) if and only if
            //s[i][j] is a white square ('.') and there is a red square ('@') next to s[i][j]

            if(s[i][j]=='.'){
                bool flag=false;
                for(int z=0;z<=3;z++){
                    ll nxt_i=i+dx[z];
                    ll nxt_j=j+dy[z];
                    if(valid(nxt_i,nxt_j) && s[nxt_i][nxt_j]=='@'){
                        flag=true;//If there is a red square next to (i, j), set flag to true
                    }
                }
                if(flag){
                    next.push_back({i,j});//add (i, j) as the next candidate of red square
                }
            }
        }
    }
    for(l_l pos:next){
        s[pos.first][pos.second]='@';//paint red
        dfs(num-1);                  //advance DFS
        s[pos.first][pos.second]='.';//clean up
    }
}

signed main(){
    ll k;cin>>n>>k;
    s.resize(n);
    for(int i=0;i<=n-1;i++)cin>>s[i];

    for(int i=0;i<=n-1;i++){
        for(int j=0;j<=n-1;j++){
            //We paint Square (i, J) first
            if(s[i][j]=='.'){
                s[i][j]='@';//paint red
                dfs(k-1);   //start DFS
                s[i][j]='.';//clean up
            }
        }
    }
    cout<<answer<<endl;
    return 0;
}

Note that the code above is a bit slow for the sake of readability.
https://atcoder.jp/contests/abc211/submissions/24453774 (541ms)

One can manage the state of board with a 64-bit integer (like unsigned long long) instead of vector<string> to speed up.
https://atcoder.jp/contests/abc211/submissions/24453782 (85ms)

With a little twist, one can avoid visiting the same board twice in the DFS.
https://atcoder.jp/contests/abc211/submissions/24453788 (25ms)

posted:
last update: