// g++ -O3 -std=c++0x iterative_o3.cc
// ./a.out < testcase.txt
// cat result.txt
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
#include <cmath>
#include <random>
#include <assert.h>
#include <sys/time.h>
#include <stdint.h>
using namespace std;
const int N = 500 ;
typedef long long LL;
class Timer{
protected :
double startTime;
public :
Timer( ) { startTime = now( ) ; }
double elapse( ) { return now( ) - startTime; }
protected :
double now( ) {
timeval tv;
gettimeofday( & tv, 0 ) ;
return tv.tv_sec + tv.tv_usec * 1e-6 ;
}
} ;
template < class T>
struct Matrix{
T data[ N* N] ;
Matrix( ) { }
Matrix( const T& init) {
for ( int y = 0 ; y < N; y++ ) {
for ( int x = 0 ; x < N; x++ ) {
data[ y* N+ x] = init;
}
}
}
const T* operator[ ] ( int y) const {
return & ( data[ y* N] ) ;
}
T* operator[ ] ( int y) {
return & ( data[ y* N] ) ;
}
} ;
Timer timer;
Matrix< int > preset;
Matrix< int > board;
mt19937_64 mt19937_obj;
LL myrand( ) {
return mt19937_obj( ) >> 1 ;
}
template < class T>
void shuffle( T b, T e) {
while ( b ! = e) {
T t = b + myrand( ) % ( e- b) ;
swap( * t, * b) ;
b++ ;
}
}
void initialize( ) {
for ( int y = 0 ; y < N; y++ ) {
for ( int x = 0 ; x < N; x++ ) {
if ( preset[ y] [ x] ) continue ;
board[ y] [ x] = 1 << ( myrand( ) % 9 + 1 ) ;
}
}
}
int calcScore( const Matrix< int > & board) ;
void writeBoard( const Matrix< int > & board, ostream& st) {
for ( int y = 0 ; y < N; y++ ) {
for ( int x = 0 ; x < N; x++ ) {
int v = 1 ;
for ( int i = 1 ; i <= 9 ; i++ ) {
if ( board[ y] [ x] == ( 1 << i) ) v = i;
}
st << v;
}
st << endl;
}
st << endl;
st << "score : " << calcScore( board) << endl;
st << "elapse : " << timer.elapse ( ) << endl;
}
void writeBoard( const Matrix< int > & board, const char * filename) {
ofstream st( filename) ;
writeBoard( board, st) ;
}
void readBoard( Matrix< int > & board, istream& st) {
for ( int y = 0 ; y < N; y++ ) {
string line;
st >> line;
for ( int x = 0 ; x < N; x++ ) {
int n = line[ x] - '0' ;
if ( n == 0 ) {
board[ y] [ x] = 0 ;
} else {
board[ y] [ x] = 1 << n;
}
if ( preset[ y] [ x] ) assert ( preset[ y] [ x] == board[ y] [ x] ) ;
}
}
}
void readBoard( Matrix< int > & board, const char * filename) {
ifstream st( filename) ;
readBoard( board, st) ;
}
int lineScoreH( const Matrix< int > & board, int x, int y, int ex) {
int state = 0 ;
int score = 0 ;
for ( int i = 0 ; i < 8 ; i++ , x++ ) {
state + = board[ y] [ x] ;
}
for ( ; x < ex; x++ ) {
state + = board[ y] [ x] ;
if ( state == 0x3fe ) score++ ;
state - = board[ y] [ x- 8 ] ;
}
return score;
}
int lineScoreV( const Matrix< int > & board, int x, int y, int ey) {
int state = 0 ;
int score = 0 ;
for ( int i = 0 ; i < 8 ; i++ , y++ ) {
state + = board[ y] [ x] ;
}
for ( ; y < ey; y++ ) {
state + = board[ y] [ x] ;
if ( state == 0x3fe ) score++ ;
state - = board[ y- 8 ] [ x] ;
}
return score;
}
int blockScore( const Matrix< int > & board, int y, int sx, int ex) {
if ( y+ 2 >= N) return 0 ;
int state = 0 ;
int score = 0 ;
int x = sx;
for ( ; x < sx+ 2 ; x++ ) {
state + = board[ y+ 0 ] [ x] ;
state + = board[ y+ 1 ] [ x] ;
state + = board[ y+ 2 ] [ x] ;
}
for ( ; x < ex; x++ ) {
state + = board[ y+ 0 ] [ x] ;
state + = board[ y+ 1 ] [ x] ;
state + = board[ y+ 2 ] [ x] ;
if ( state == 0x3fe ) score++ ;
state - = board[ y+ 0 ] [ x- 2 ] ;
state - = board[ y+ 1 ] [ x- 2 ] ;
state - = board[ y+ 2 ] [ x- 2 ] ;
}
return score;
}
int calcScore( const Matrix< int > & board) {
int score = 0 ;
for ( int y = 0 ; y < N; y++ ) {
score + = lineScoreH( board, 0 , y, N) ;
score + = lineScoreV( board, y, 0 , N) ;
}
for ( int y = 0 ; y+ 2 < N; y++ ) {
score + = blockScore( board, y, 0 , N) ;
}
return score;
}
int partialScore( Matrix< int > & board, int x, int y) {
int score = 0 ;
score + = lineScoreH( board, max( 0 ,x- 8 ) , y, min( N,x+ 9 ) ) ;
score + = lineScoreV( board, x, max( 0 ,y- 8 ) , min( N,y+ 9 ) ) ;
for ( int y2 = max( 0 ,y- 2 ) ; y2 <= y; y2++ ) {
score + = blockScore( board, y2, max( 0 ,x- 2 ) , min( N,x+ 3 ) ) ;
}
return score;
}
const int one_left_tbl[ ] = { 1 << 5 ,1 << 6 ,1 << 3 ,1 << 7 ,1 << 9 ,1 << 4 ,1 << 2 ,1 << 8 ,1 << 1 ,0 ,0 } ;
const int one_left_tbl_width = 11 ;
struct OneLeft{
int16_t x;
int16_t y;
int to_be;
OneLeft( ) { }
OneLeft( int x_, int y_, int to_be_) : x( x_) ,y( y_) ,to_be( to_be_) { }
} ;
void getOneLeftLineH( const Matrix< int > & board, int x, int y, vector< OneLeft> & res) {
int cnt = 0 ;
int cnt2 = 0 ;
for ( int i = 0 ; i < 9 ; i++ ) {
cnt | = board[ y] [ x+ i] ;
cnt2 ^ = board[ y] [ x+ i] ;
}
int to_be = one_left_tbl[ cnt % one_left_tbl_width] ;
if ( ( cnt | to_be) ! = 0x3fe ) return ;
int v = one_left_tbl[ ( cnt2| to_be) % one_left_tbl_width] ;
for ( int i = 0 ; i < 9 ; i++ ) {
if ( board[ y] [ x+ i] == v && ! preset[ y] [ x+ i] ) {
res.push_back ( OneLeft( x+ i, y, to_be) ) ;
}
}
}
void getOneLeftLineV( const Matrix< int > & board, int x, int y, vector< OneLeft> & res) {
int cnt = 0 ;
int cnt2 = 0 ;
for ( int y2 = y; y2 < y+ 9 ; y2++ ) {
cnt | = board[ y2] [ x] ;
cnt2 ^ = board[ y2] [ x] ;
}
int to_be = one_left_tbl[ cnt % one_left_tbl_width] ;
if ( ( cnt | to_be) ! = 0x3fe ) return ;
int v = one_left_tbl[ ( cnt2| to_be) % one_left_tbl_width] ;
for ( int y2 = y; y2 < y+ 9 ; y2++ ) {
if ( board[ y2] [ x] == v && ! preset[ y2] [ x] ) {
res.push_back ( OneLeft( x, y2, to_be) ) ;
}
}
}
void getOneLeftBlock( const Matrix< int > & board, int x, int y, vector< OneLeft> & res) {
int cnt = 0 ;
int cnt2 = 0 ;
for ( int y2 = y; y2 < y+ 3 ; y2++ ) {
cnt | = board[ y2] [ x+ 0 ] ;
cnt2 ^ = board[ y2] [ x+ 0 ] ;
cnt | = board[ y2] [ x+ 1 ] ;
cnt2 ^ = board[ y2] [ x+ 1 ] ;
cnt | = board[ y2] [ x+ 2 ] ;
cnt2 ^ = board[ y2] [ x+ 2 ] ;
}
int to_be = one_left_tbl[ cnt % one_left_tbl_width] ;
if ( ( cnt | to_be) ! = 0x3fe ) return ;
int v = one_left_tbl[ ( cnt2| to_be) % one_left_tbl_width] ;
for ( int y2 = y; y2 < y+ 3 ; y2++ ) {
for ( int dx = 0 ; dx < 3 ; dx++ ) {
if ( board[ y2] [ x+ dx] == v && ! preset[ y2] [ x+ dx] ) {
res.push_back ( OneLeft( x+ dx, y2, to_be) ) ;
}
}
}
}
void getOneLeft( const Matrix< int > & board, int x, int y, vector< OneLeft> & res) {
for ( int x2 = max( 0 ,x- 8 ) ; x2 <= min( x, N- 9 ) ; x2++ ) {
getOneLeftLineH( board, x2, y, res) ;
}
for ( int y2 = max( 0 ,y- 8 ) ; y2 <= min( y, N- 9 ) ; y2++ ) {
getOneLeftLineV( board, x, y2, res) ;
}
for ( int x2 = max( 0 ,x- 2 ) ; x2 <= min( x, N- 3 ) ; x2++ ) {
for ( int y2 = max( 0 ,y- 2 ) ; y2 <= min( y, N- 3 ) ; y2++ ) {
getOneLeftBlock( board, x2, y2, res) ;
}
}
}
int rollbackHistory( Matrix< int > & board, vector< pair< int ,int > > & history, int history_idx, int score) {
if ( history.empty ( ) ) return score;
for ( int i = history.size ( ) - 1 ; i >= history_idx; i-- ) {
int x2 = history[ i] .first % N;
int y2 = history[ i] .first / N;
board[ y2] [ x2] = history[ i] .second >> 20 ;
}
score = history[ history_idx] .second & ( ( 1 << 20 ) - 1 ) ;
history.resize ( history_idx) ;
return score;
}
static int HASH_W = 29 ;
uint64_t updateHash( uint64_t hash, int x, int y, int n) {
return hash ^ ( 0x510990bf819745cLL / ( ( ( x * 500 + y) << 10 ) + n+ 1 ) ) ;
}
int search_best = 0 ;
int search( Matrix< int > & board, int x, int y, int depth, int score, int best, vector< pair< int ,int > > & history, uint64_t hash, vector< int > & memo, const int hash_v) {
//if(depth > 15) return score;
if ( depth > 10 ) return score;
if ( score < search_best - 25 ) return score;
int search_w = 4 ;
vector< OneLeft> one_left;
one_left.reserve ( 250 ) ;
getOneLeft( board, x, y, one_left) ;
shuffle( one_left.begin ( ) , one_left.end ( ) ) ;
int history_idx = history.size ( ) ;
for ( int i = 0 ; i < search_w && i < one_left.size ( ) ; i++ ) {
int x2 = one_left[ i] .x ;
int y2 = one_left[ i] .y ;
int n = one_left[ i] .to_be ;
if ( preset[ y2] [ x2] || board[ y2] [ x2] == n) continue ;
if ( x2== x && y2== y && depth > 0 ) {
search_w++ ;
continue ;
}
if ( depth == 0 && ( x2! = x || y2! = y) ) {
search_w++ ;
continue ;
}
uint64_t new_hash = updateHash( hash, x2, y2, n) ;
if ( memo[ new_hash & ( ( 1ULL<< HASH_W) - 1 ) ] == hash_v) {
continue ;
}
int history_idx2 = history.size ( ) ;
history.push_back ( pair< int ,int > ( y2* N+ x2, score+ ( board[ y2] [ x2] << 20 ) ) ) ;
int org_score = score;
int prev_score = partialScore( board, x2, y2) ;
board[ y2] [ x2] = n;
int new_score = partialScore( board, x2, y2) ;
score + = new_score - prev_score;
score = search( board, x2, y2, depth+ 1 , score, best, history, new_hash, memo, hash_v) ;
if ( score < org_score) {
score = rollbackHistory( board, history, history_idx2, score) ;
// memory no changes
memo[ new_hash & ( ( 1ULL<< HASH_W) - 1 ) ] = hash_v;
} else {
hash = new_hash;
}
}
return score;
}
int search( Matrix< int > & board, int x, int y, int best, vector< int > & memo, const int hash_v) {
search_best = best;
vector< pair< int ,int > > history;
history.reserve ( 4090 ) ;
int score = search( board, x, y, 0 , best, best, history, 0 , memo, hash_v) ;
if ( score < best) {
score = rollbackHistory( board, history, 0 , score) ;
}
return score;
}
void optimize( ) {
initialize( ) ;
int best = calcScore( board) ;
int e2 = 0 ;
while ( true ) {
vector< int > memo( 1ULL<< HASH_W) ;
for ( int y = 0 ; y < N; y++ ) {
for ( int x = 0 ; x < N; x++ ) {
best = search( board, x, y, best, memo, x+ y* N) ;
}
cerr << e2 << " : " << y << " , " << best << " , " << timer.elapse ( ) << endl;
}
writeBoard( board, "result.txt" ) ;
assert ( best == calcScore( board) ) ;
e2++ ;
}
}
int main( ) {
readBoard( board, cin ) ;
preset = board;
optimize( ) ;
return 0 ;
}
Ly8gZysrIC1PMyAtc3RkPWMrKzB4IGl0ZXJhdGl2ZV9vMy5jYwovLyAuL2Eub3V0IDwgdGVzdGNhc2UudHh0Ci8vIGNhdCByZXN1bHQudHh0CiNpbmNsdWRlIDxpb3N0cmVhbT4KI2luY2x1ZGUgPGZzdHJlYW0+CiNpbmNsdWRlIDxzdHJpbmc+CiNpbmNsdWRlIDx2ZWN0b3I+CiNpbmNsdWRlIDxhbGdvcml0aG0+CiNpbmNsdWRlIDxjbWF0aD4KI2luY2x1ZGUgPHJhbmRvbT4KI2luY2x1ZGUgPGFzc2VydC5oPgojaW5jbHVkZSA8c3lzL3RpbWUuaD4KI2luY2x1ZGUgPHN0ZGludC5oPgoKdXNpbmcgbmFtZXNwYWNlIHN0ZDsKY29uc3QgaW50IE4gPSA1MDA7CnR5cGVkZWYgbG9uZyBsb25nIExMOwoKY2xhc3MgVGltZXJ7CnByb3RlY3RlZDoKICAgIGRvdWJsZSBzdGFydFRpbWU7CnB1YmxpYzoKICAgIFRpbWVyKCl7IHN0YXJ0VGltZSA9IG5vdygpOyB9CiAgICBkb3VibGUgZWxhcHNlKCl7IHJldHVybiBub3coKSAtIHN0YXJ0VGltZTsgfQpwcm90ZWN0ZWQ6CiAgICBkb3VibGUgbm93KCl7CiAgICAgICAgdGltZXZhbCB0djsKICAgICAgICBnZXR0aW1lb2ZkYXkoJnR2LCAwKTsKICAgICAgICByZXR1cm4gdHYudHZfc2VjICsgdHYudHZfdXNlYyAqIDFlLTY7CiAgICB9Cn07Cgp0ZW1wbGF0ZSA8Y2xhc3MgVD4Kc3RydWN0IE1hdHJpeHsKICAgIFQgZGF0YVtOKk5dOwogICAgTWF0cml4KCl7fQogICAgTWF0cml4KGNvbnN0IFQmIGluaXQpewogICAgICAgIGZvcihpbnQgeSA9IDA7eSA8IE47IHkrKyl7CiAgICAgICAgICAgIGZvcihpbnQgeCA9IDA7eCA8IE47IHgrKyl7CiAgICAgICAgICAgICAgICBkYXRhW3kqTit4XSA9IGluaXQ7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9CiAgICBjb25zdCBUKiBvcGVyYXRvcltdKGludCB5KSBjb25zdHsKICAgICAgICByZXR1cm4gJihkYXRhW3kqTl0pOwogICAgfQogICAgVCogb3BlcmF0b3JbXShpbnQgeSl7CiAgICAgICAgcmV0dXJuICYoZGF0YVt5Kk5dKTsKICAgIH0KfTsKClRpbWVyIHRpbWVyOwpNYXRyaXg8aW50PiBwcmVzZXQ7Ck1hdHJpeDxpbnQ+IGJvYXJkOwoKbXQxOTkzN182NCBtdDE5OTM3X29iajsKTEwgbXlyYW5kKCl7CiAgICByZXR1cm4gbXQxOTkzN19vYmooKSA+PiAxOwp9Cgp0ZW1wbGF0ZSA8Y2xhc3MgVD4Kdm9pZCBzaHVmZmxlKFQgYiwgVCBlKXsKICAgIHdoaWxlKGIgIT0gZSl7CiAgICAgICAgVCB0ID0gYiArIG15cmFuZCgpICUgKGUtYik7CiAgICAgICAgc3dhcCgqdCwgKmIpOwogICAgICAgIGIrKzsKICAgIH0KfQoKdm9pZCBpbml0aWFsaXplKCl7CiAgICBmb3IoaW50IHkgPSAwOyB5IDwgTjsgeSsrKXsKICAgICAgICBmb3IoaW50IHggPSAwOyB4IDwgTjsgeCsrKXsKICAgICAgICAgICAgaWYocHJlc2V0W3ldW3hdKSBjb250aW51ZTsKICAgICAgICAgICAgYm9hcmRbeV1beF0gPSAxPDwobXlyYW5kKCklOSsxKTsKICAgICAgICB9CiAgICB9Cn0KCmludCBjYWxjU2NvcmUoY29uc3QgTWF0cml4PGludD4mIGJvYXJkKTsKdm9pZCB3cml0ZUJvYXJkKGNvbnN0IE1hdHJpeDxpbnQ+JiBib2FyZCwgb3N0cmVhbSYgc3QpewogICAgZm9yKGludCB5ID0gMDsgeSA8IE47IHkrKyl7CiAgICAgICAgZm9yKGludCB4ID0gMDsgeCA8IE47IHgrKyl7CiAgICAgICAgICAgIGludCB2ID0gMTsKICAgICAgICAgICAgZm9yKGludCBpID0gMTsgaSA8PSA5OyBpKyspewogICAgICAgICAgICAgICAgaWYoYm9hcmRbeV1beF0gPT0gKDE8PGkpKSB2ID0gaTsKICAgICAgICAgICAgfQogICAgICAgICAgICBzdCA8PCB2OwogICAgICAgIH0KICAgICAgICBzdCA8PCBlbmRsOwogICAgfQogICAgc3QgPDwgZW5kbDsKICAgIHN0IDw8ICJzY29yZSA6ICIgPDwgY2FsY1Njb3JlKGJvYXJkKSA8PCBlbmRsOwogICAgc3QgPDwgImVsYXBzZSA6ICIgPDwgdGltZXIuZWxhcHNlKCkgPDwgZW5kbDsKfQoKdm9pZCB3cml0ZUJvYXJkKGNvbnN0IE1hdHJpeDxpbnQ+JiBib2FyZCwgY29uc3QgY2hhciogZmlsZW5hbWUpewogICAgb2ZzdHJlYW0gc3QoZmlsZW5hbWUpOwogICAgd3JpdGVCb2FyZChib2FyZCwgc3QpOwp9Cgp2b2lkIHJlYWRCb2FyZChNYXRyaXg8aW50PiYgYm9hcmQsIGlzdHJlYW0mIHN0KXsKICAgIGZvcihpbnQgeSA9IDA7IHkgPCBOOyB5KyspewogICAgICAgIHN0cmluZyBsaW5lOwogICAgICAgIHN0ID4+IGxpbmU7CiAgICAgICAgZm9yKGludCB4ID0gMDsgeCA8IE47IHgrKyl7CiAgICAgICAgICAgIGludCBuID0gbGluZVt4XS0nMCc7CiAgICAgICAgICAgIGlmKG4gPT0gMCl7CiAgICAgICAgICAgICAgICBib2FyZFt5XVt4XSA9IDA7CiAgICAgICAgICAgIH1lbHNlewogICAgICAgICAgICAgICAgYm9hcmRbeV1beF0gPSAxPDxuOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmKHByZXNldFt5XVt4XSkgYXNzZXJ0KHByZXNldFt5XVt4XSA9PSBib2FyZFt5XVt4XSk7CiAgICAgICAgfQogICAgfQp9Cgp2b2lkIHJlYWRCb2FyZChNYXRyaXg8aW50PiYgYm9hcmQsIGNvbnN0IGNoYXIqIGZpbGVuYW1lKXsKICAgIGlmc3RyZWFtIHN0KGZpbGVuYW1lKTsKICAgIHJlYWRCb2FyZChib2FyZCwgc3QpOwp9CgppbnQgbGluZVNjb3JlSChjb25zdCBNYXRyaXg8aW50PiYgYm9hcmQsIGludCB4LCBpbnQgeSwgaW50IGV4KXsKICAgIGludCBzdGF0ZSA9IDA7CiAgICBpbnQgc2NvcmUgPSAwOwogICAgZm9yKGludCBpID0gMDsgaSA8IDg7IGkrKywgeCsrKXsKICAgICAgICBzdGF0ZSArPSBib2FyZFt5XVt4XTsKICAgIH0KICAgIGZvcig7IHggPCBleDsgeCsrKXsKICAgICAgICBzdGF0ZSArPSBib2FyZFt5XVt4XTsKICAgICAgICBpZihzdGF0ZSA9PSAweDNmZSkgc2NvcmUrKzsKICAgICAgICBzdGF0ZSAtPSBib2FyZFt5XVt4LThdOwogICAgfQogICAgcmV0dXJuIHNjb3JlOwp9CgppbnQgbGluZVNjb3JlVihjb25zdCBNYXRyaXg8aW50PiYgYm9hcmQsIGludCB4LCBpbnQgeSwgaW50IGV5KXsKICAgIGludCBzdGF0ZSA9IDA7CiAgICBpbnQgc2NvcmUgPSAwOwogICAgZm9yKGludCBpID0gMDsgaSA8IDg7IGkrKywgeSsrKXsKICAgICAgICBzdGF0ZSArPSBib2FyZFt5XVt4XTsKICAgIH0KICAgIGZvcig7IHkgPCBleTsgeSsrKXsKICAgICAgICBzdGF0ZSArPSBib2FyZFt5XVt4XTsKICAgICAgICBpZihzdGF0ZSA9PSAweDNmZSkgc2NvcmUrKzsKICAgICAgICBzdGF0ZSAtPSBib2FyZFt5LThdW3hdOwogICAgfQogICAgcmV0dXJuIHNjb3JlOwp9CgppbnQgYmxvY2tTY29yZShjb25zdCBNYXRyaXg8aW50PiYgYm9hcmQsIGludCB5LCBpbnQgc3gsIGludCBleCl7CiAgICBpZih5KzIgPj0gTikgcmV0dXJuIDA7CiAgICBpbnQgc3RhdGUgPSAwOwogICAgaW50IHNjb3JlID0gMDsKICAgIGludCB4ID0gc3g7CiAgICBmb3IoOyB4IDwgc3grMjsgeCsrKXsKICAgICAgICBzdGF0ZSArPSBib2FyZFt5KzBdW3hdOwogICAgICAgIHN0YXRlICs9IGJvYXJkW3krMV1beF07CiAgICAgICAgc3RhdGUgKz0gYm9hcmRbeSsyXVt4XTsKICAgIH0KICAgIGZvcig7IHggPCBleDsgeCsrKXsKICAgICAgICBzdGF0ZSArPSBib2FyZFt5KzBdW3hdOwogICAgICAgIHN0YXRlICs9IGJvYXJkW3krMV1beF07CiAgICAgICAgc3RhdGUgKz0gYm9hcmRbeSsyXVt4XTsKICAgICAgICBpZihzdGF0ZSA9PSAweDNmZSkgc2NvcmUrKzsKICAgICAgICBzdGF0ZSAtPSBib2FyZFt5KzBdW3gtMl07CiAgICAgICAgc3RhdGUgLT0gYm9hcmRbeSsxXVt4LTJdOwogICAgICAgIHN0YXRlIC09IGJvYXJkW3krMl1beC0yXTsKICAgIH0KICAgIHJldHVybiBzY29yZTsKfQoKaW50IGNhbGNTY29yZShjb25zdCBNYXRyaXg8aW50PiYgYm9hcmQpewogICAgaW50IHNjb3JlID0gMDsKICAgIGZvcihpbnQgeSA9IDA7IHkgPCBOOyB5KyspewogICAgICAgIHNjb3JlICs9IGxpbmVTY29yZUgoYm9hcmQsIDAsIHksIE4pOwogICAgICAgIHNjb3JlICs9IGxpbmVTY29yZVYoYm9hcmQsIHksIDAsIE4pOwogICAgfQogICAgZm9yKGludCB5ID0gMDsgeSsyIDwgTjsgeSsrKXsKICAgICAgICBzY29yZSArPSBibG9ja1Njb3JlKGJvYXJkLCB5LCAwLCBOKTsKICAgIH0KICAgIHJldHVybiBzY29yZTsKfQoKaW50IHBhcnRpYWxTY29yZShNYXRyaXg8aW50PiYgYm9hcmQsIGludCB4LCBpbnQgeSl7CiAgICBpbnQgc2NvcmUgPSAwOwogICAgc2NvcmUgKz0gbGluZVNjb3JlSChib2FyZCwgbWF4KDAseC04KSwgeSwgbWluKE4seCs5KSk7CiAgICBzY29yZSArPSBsaW5lU2NvcmVWKGJvYXJkLCB4LCBtYXgoMCx5LTgpLCBtaW4oTix5KzkpKTsKICAgIGZvcihpbnQgeTIgPSBtYXgoMCx5LTIpOyB5MiA8PSB5OyB5MisrKXsKICAgICAgICBzY29yZSArPSBibG9ja1Njb3JlKGJvYXJkLCB5MiwgbWF4KDAseC0yKSwgbWluKE4seCszKSk7CiAgICB9CiAgICByZXR1cm4gc2NvcmU7Cn0KCmNvbnN0IGludCBvbmVfbGVmdF90YmxbXSA9IHsxPDw1LDE8PDYsMTw8MywxPDw3LDE8PDksMTw8NCwxPDwyLDE8PDgsMTw8MSwwLDB9Owpjb25zdCBpbnQgb25lX2xlZnRfdGJsX3dpZHRoID0gMTE7CgpzdHJ1Y3QgT25lTGVmdHsKICAgIGludDE2X3QgeDsKICAgIGludDE2X3QgeTsKICAgIGludCB0b19iZTsKICAgIE9uZUxlZnQoKXt9CiAgICBPbmVMZWZ0KGludCB4XywgaW50IHlfLCBpbnQgdG9fYmVfKTp4KHhfKSx5KHlfKSx0b19iZSh0b19iZV8pe30KfTsKCnZvaWQgZ2V0T25lTGVmdExpbmVIKGNvbnN0IE1hdHJpeDxpbnQ+JiBib2FyZCwgaW50IHgsIGludCB5LCB2ZWN0b3I8T25lTGVmdD4mIHJlcyl7CiAgICBpbnQgY250ID0gMDsKICAgIGludCBjbnQyID0gMDsKICAgIGZvcihpbnQgaSA9IDA7IGkgPCA5OyBpKyspewogICAgICAgIGNudCB8PSBib2FyZFt5XVt4K2ldOwogICAgICAgIGNudDIgXj0gYm9hcmRbeV1beCtpXTsKICAgIH0KICAgIGludCB0b19iZSA9IG9uZV9sZWZ0X3RibFtjbnQgJSBvbmVfbGVmdF90Ymxfd2lkdGhdOwogICAgaWYoKGNudCB8IHRvX2JlKSAhPSAweDNmZSkgcmV0dXJuOwogICAgaW50IHYgPSBvbmVfbGVmdF90YmxbKGNudDJ8dG9fYmUpICUgb25lX2xlZnRfdGJsX3dpZHRoXTsKICAgIGZvcihpbnQgaSA9IDA7IGkgPCA5OyBpKyspewogICAgICAgIGlmKGJvYXJkW3ldW3graV0gPT0gdiAmJiAhcHJlc2V0W3ldW3graV0pewogICAgICAgICAgICByZXMucHVzaF9iYWNrKE9uZUxlZnQoeCtpLCB5LCB0b19iZSkpOwogICAgICAgIH0KICAgIH0KfQoKdm9pZCBnZXRPbmVMZWZ0TGluZVYoY29uc3QgTWF0cml4PGludD4mIGJvYXJkLCBpbnQgeCwgaW50IHksIHZlY3RvcjxPbmVMZWZ0PiYgcmVzKXsKICAgIGludCBjbnQgPSAwOwogICAgaW50IGNudDIgPSAwOwogICAgZm9yKGludCB5MiA9IHk7IHkyIDwgeSs5OyB5MisrKXsKICAgICAgICBjbnQgfD0gYm9hcmRbeTJdW3hdOwogICAgICAgIGNudDIgXj0gYm9hcmRbeTJdW3hdOwogICAgfQogICAgaW50IHRvX2JlID0gb25lX2xlZnRfdGJsW2NudCAlIG9uZV9sZWZ0X3RibF93aWR0aF07CiAgICBpZigoY250IHwgdG9fYmUpICE9IDB4M2ZlKSByZXR1cm47CiAgICBpbnQgdiA9IG9uZV9sZWZ0X3RibFsoY250Mnx0b19iZSkgJSBvbmVfbGVmdF90Ymxfd2lkdGhdOwogICAgZm9yKGludCB5MiA9IHk7IHkyIDwgeSs5OyB5MisrKXsKICAgICAgICBpZihib2FyZFt5Ml1beF0gPT0gdiAmJiAhcHJlc2V0W3kyXVt4XSl7CiAgICAgICAgICAgIHJlcy5wdXNoX2JhY2soT25lTGVmdCh4LCB5MiwgdG9fYmUpKTsKICAgICAgICB9CiAgICB9Cn0KCnZvaWQgZ2V0T25lTGVmdEJsb2NrKGNvbnN0IE1hdHJpeDxpbnQ+JiBib2FyZCwgaW50IHgsIGludCB5LCB2ZWN0b3I8T25lTGVmdD4mIHJlcyl7CiAgICBpbnQgY250ID0gMDsKICAgIGludCBjbnQyID0gMDsKICAgIGZvcihpbnQgeTIgPSB5OyB5MiA8IHkrMzsgeTIrKyl7CiAgICAgICAgY250IHw9IGJvYXJkW3kyXVt4KzBdOwogICAgICAgIGNudDIgXj0gYm9hcmRbeTJdW3grMF07CiAgICAgICAgY250IHw9IGJvYXJkW3kyXVt4KzFdOwogICAgICAgIGNudDIgXj0gYm9hcmRbeTJdW3grMV07CiAgICAgICAgY250IHw9IGJvYXJkW3kyXVt4KzJdOwogICAgICAgIGNudDIgXj0gYm9hcmRbeTJdW3grMl07CiAgICB9CiAgICBpbnQgdG9fYmUgPSBvbmVfbGVmdF90YmxbY250ICUgb25lX2xlZnRfdGJsX3dpZHRoXTsKICAgIGlmKChjbnQgfCB0b19iZSkgIT0gMHgzZmUpIHJldHVybjsKICAgIGludCB2ID0gb25lX2xlZnRfdGJsWyhjbnQyfHRvX2JlKSAlIG9uZV9sZWZ0X3RibF93aWR0aF07CiAgICBmb3IoaW50IHkyID0geTsgeTIgPCB5KzM7IHkyKyspewogICAgICAgIGZvcihpbnQgZHggPSAwOyBkeCA8IDM7IGR4KyspewogICAgICAgICAgICBpZihib2FyZFt5Ml1beCtkeF0gPT0gdiAmJiAhcHJlc2V0W3kyXVt4K2R4XSl7CiAgICAgICAgICAgICAgICByZXMucHVzaF9iYWNrKE9uZUxlZnQoeCtkeCwgeTIsIHRvX2JlKSk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9Cn0KCnZvaWQgZ2V0T25lTGVmdChjb25zdCBNYXRyaXg8aW50PiYgYm9hcmQsIGludCB4LCBpbnQgeSwgdmVjdG9yPE9uZUxlZnQ+JiByZXMpewogICAgZm9yKGludCB4MiA9IG1heCgwLHgtOCk7IHgyIDw9IG1pbih4LCBOLTkpOyB4MisrKXsKICAgICAgICBnZXRPbmVMZWZ0TGluZUgoYm9hcmQsIHgyLCB5LCByZXMpOwogICAgfQogICAgZm9yKGludCB5MiA9IG1heCgwLHktOCk7IHkyIDw9IG1pbih5LCBOLTkpOyB5MisrKXsKICAgICAgICBnZXRPbmVMZWZ0TGluZVYoYm9hcmQsIHgsIHkyLCByZXMpOwogICAgfQogICAgZm9yKGludCB4MiA9IG1heCgwLHgtMik7IHgyIDw9IG1pbih4LCBOLTMpOyB4MisrKXsKICAgICAgICBmb3IoaW50IHkyID0gbWF4KDAseS0yKTsgeTIgPD0gbWluKHksIE4tMyk7IHkyKyspewogICAgICAgICAgICBnZXRPbmVMZWZ0QmxvY2soYm9hcmQsIHgyLCB5MiwgcmVzKTsKICAgICAgICB9CiAgICB9Cn0KCmludCByb2xsYmFja0hpc3RvcnkoTWF0cml4PGludD4mIGJvYXJkLCB2ZWN0b3I8cGFpcjxpbnQsaW50PiA+JiBoaXN0b3J5LCBpbnQgaGlzdG9yeV9pZHgsIGludCBzY29yZSl7CiAgICBpZihoaXN0b3J5LmVtcHR5KCkpIHJldHVybiBzY29yZTsKICAgIGZvcihpbnQgaSA9IGhpc3Rvcnkuc2l6ZSgpLTE7IGkgPj0gaGlzdG9yeV9pZHg7IGktLSl7CiAgICAgICAgaW50IHgyID0gaGlzdG9yeVtpXS5maXJzdCAlIE47CiAgICAgICAgaW50IHkyID0gaGlzdG9yeVtpXS5maXJzdCAvIE47CiAgICAgICAgYm9hcmRbeTJdW3gyXSA9IGhpc3RvcnlbaV0uc2Vjb25kID4+IDIwOwogICAgfQogICAgc2NvcmUgPSBoaXN0b3J5W2hpc3RvcnlfaWR4XS5zZWNvbmQgJiAoKDE8PDIwKS0xKTsKICAgIGhpc3RvcnkucmVzaXplKGhpc3RvcnlfaWR4KTsKICAgIHJldHVybiBzY29yZTsKfQoKc3RhdGljIGludCBIQVNIX1cgPSAyOTsKdWludDY0X3QgdXBkYXRlSGFzaCh1aW50NjRfdCBoYXNoLCBpbnQgeCwgIGludCB5LCBpbnQgbil7CiAgICByZXR1cm4gaGFzaCBeICgweDUxMDk5MGJmODE5NzQ1Y0xMIC8gKCgoeCAqIDUwMCArIHkpIDw8IDEwKSArIG4rMSkpOwp9CgppbnQgc2VhcmNoX2Jlc3QgPSAwOwppbnQgc2VhcmNoKE1hdHJpeDxpbnQ+JiBib2FyZCwgaW50IHgsIGludCB5LCBpbnQgZGVwdGgsIGludCBzY29yZSwgaW50IGJlc3QsIHZlY3RvcjxwYWlyPGludCxpbnQ+ID4mIGhpc3RvcnksIHVpbnQ2NF90IGhhc2gsIHZlY3RvcjxpbnQ+JiBtZW1vLCBjb25zdCBpbnQgaGFzaF92KXsKICAgIC8vaWYoZGVwdGggPiAxNSkgcmV0dXJuIHNjb3JlOwogICAgaWYoZGVwdGggPiAxMCkgcmV0dXJuIHNjb3JlOwogICAgaWYoc2NvcmUgPCBzZWFyY2hfYmVzdCAtIDI1KSByZXR1cm4gc2NvcmU7CgogICAgaW50IHNlYXJjaF93ID0gNDsKICAgIHZlY3RvcjxPbmVMZWZ0PiBvbmVfbGVmdDsKICAgIG9uZV9sZWZ0LnJlc2VydmUoMjUwKTsKICAgIGdldE9uZUxlZnQoYm9hcmQsIHgsIHksIG9uZV9sZWZ0KTsKICAgIHNodWZmbGUob25lX2xlZnQuYmVnaW4oKSwgb25lX2xlZnQuZW5kKCkpOwogICAgaW50IGhpc3RvcnlfaWR4ID0gaGlzdG9yeS5zaXplKCk7CiAgICBmb3IoaW50IGkgPSAwOyBpIDwgc2VhcmNoX3cgJiYgaSA8IG9uZV9sZWZ0LnNpemUoKTsgaSsrKXsKICAgICAgICBpbnQgeDIgPSBvbmVfbGVmdFtpXS54OwogICAgICAgIGludCB5MiA9IG9uZV9sZWZ0W2ldLnk7CiAgICAgICAgaW50IG4gPSBvbmVfbGVmdFtpXS50b19iZTsKICAgICAgICBpZihwcmVzZXRbeTJdW3gyXSB8fCBib2FyZFt5Ml1beDJdPT1uKSBjb250aW51ZTsKICAgICAgICBpZih4Mj09eCAmJiB5Mj09eSAmJiBkZXB0aCA+IDApewogICAgICAgICAgICBzZWFyY2hfdysrOwogICAgICAgICAgICBjb250aW51ZTsKICAgICAgICB9CiAgICAgICAgaWYoZGVwdGggPT0gMCAmJiAoeDIhPXggfHwgeTIhPXkpKXsKICAgICAgICAgICAgc2VhcmNoX3crKzsKICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgfQogICAgICAgIHVpbnQ2NF90IG5ld19oYXNoID0gdXBkYXRlSGFzaChoYXNoLCB4MiwgeTIsIG4pOwogICAgICAgIGlmKG1lbW9bbmV3X2hhc2ggJiAoKDFVTEw8PEhBU0hfVyktMSldID09IGhhc2hfdil7CiAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgIH0KICAgICAgICBpbnQgaGlzdG9yeV9pZHgyID0gaGlzdG9yeS5zaXplKCk7CiAgICAgICAgaGlzdG9yeS5wdXNoX2JhY2socGFpcjxpbnQsaW50Pih5MipOK3gyLCBzY29yZSsoYm9hcmRbeTJdW3gyXTw8MjApKSk7CiAgICAgICAgaW50IG9yZ19zY29yZSA9IHNjb3JlOwogICAgICAgIGludCBwcmV2X3Njb3JlID0gcGFydGlhbFNjb3JlKGJvYXJkLCB4MiwgeTIpOwogICAgICAgIGJvYXJkW3kyXVt4Ml0gPSBuOwogICAgICAgIGludCBuZXdfc2NvcmUgPSBwYXJ0aWFsU2NvcmUoYm9hcmQsIHgyLCB5Mik7CiAgICAgICAgc2NvcmUgKz0gbmV3X3Njb3JlIC0gcHJldl9zY29yZTsKICAgICAgICBzY29yZSA9IHNlYXJjaChib2FyZCwgeDIsIHkyLCBkZXB0aCsxLCBzY29yZSwgYmVzdCwgaGlzdG9yeSwgbmV3X2hhc2gsIG1lbW8sIGhhc2hfdik7CiAgICAgICAgaWYoc2NvcmUgPCBvcmdfc2NvcmUpewogICAgICAgICAgICBzY29yZSA9IHJvbGxiYWNrSGlzdG9yeShib2FyZCwgaGlzdG9yeSwgaGlzdG9yeV9pZHgyLCBzY29yZSk7CiAgICAgICAgICAgIC8vIG1lbW9yeSBubyBjaGFuZ2VzCiAgICAgICAgICAgIG1lbW9bbmV3X2hhc2ggJiAoKDFVTEw8PEhBU0hfVyktMSldID0gaGFzaF92OwogICAgICAgIH1lbHNlewogICAgICAgICAgICBoYXNoID0gbmV3X2hhc2g7CiAgICAgICAgfQogICAgfQogICAgcmV0dXJuIHNjb3JlOwp9CgppbnQgc2VhcmNoKE1hdHJpeDxpbnQ+JiBib2FyZCwgaW50IHgsIGludCB5LCBpbnQgYmVzdCwgdmVjdG9yPGludD4mIG1lbW8sIGNvbnN0IGludCBoYXNoX3YpewogICAgc2VhcmNoX2Jlc3QgPSBiZXN0OwogICAgdmVjdG9yPHBhaXI8aW50LGludD4gPiBoaXN0b3J5OwogICAgaGlzdG9yeS5yZXNlcnZlKDQwOTApOwogICAgaW50IHNjb3JlID0gc2VhcmNoKGJvYXJkLCB4LCB5LCAwLCBiZXN0LCBiZXN0LCBoaXN0b3J5LCAwLCBtZW1vLCBoYXNoX3YpOwogICAgaWYoc2NvcmUgPCBiZXN0KXsKICAgICAgICBzY29yZSA9IHJvbGxiYWNrSGlzdG9yeShib2FyZCwgaGlzdG9yeSwgMCwgc2NvcmUpOwogICAgfQogICAgcmV0dXJuIHNjb3JlOwp9Cgp2b2lkIG9wdGltaXplKCl7CiAgICBpbml0aWFsaXplKCk7CiAgICBpbnQgYmVzdCA9IGNhbGNTY29yZShib2FyZCk7CiAgICBpbnQgZTIgPSAwOwogICAgd2hpbGUodHJ1ZSl7CiAgICAgICAgdmVjdG9yPGludD4gbWVtbygxVUxMPDxIQVNIX1cpOwogICAgICAgIGZvcihpbnQgeSA9IDA7IHkgPCBOOyB5KyspewogICAgICAgICAgICBmb3IoaW50IHggPSAwOyB4IDwgTjsgeCsrKXsKICAgICAgICAgICAgICAgIGJlc3QgPSBzZWFyY2goYm9hcmQsIHgsIHksIGJlc3QsIG1lbW8sIHgreSpOKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBjZXJyIDw8IGUyIDw8ICIgOiAiIDw8IHkgPDwgIiAsICIgPDwgYmVzdCA8PCAiICwgIiA8PCB0aW1lci5lbGFwc2UoKSA8PCBlbmRsOwogICAgICAgIH0KICAgICAgICB3cml0ZUJvYXJkKGJvYXJkLCAicmVzdWx0LnR4dCIpOwogICAgICAgIGFzc2VydChiZXN0ID09IGNhbGNTY29yZShib2FyZCkpOwogICAgICAgIGUyKys7CiAgICB9Cn0KCmludCBtYWluKCl7CiAgICByZWFkQm9hcmQoYm9hcmQsIGNpbik7CiAgICBwcmVzZXQgPSBib2FyZDsKICAgIG9wdGltaXplKCk7CiAgICByZXR1cm4gMDsKfQo=