#include #include #include #include #include #include #include #include using namespace std; inline unsigned int asm_mul_hi(unsigned int x, unsigned int y) { __asm__ __volatile__("mul %%edx" : "+a"(x), "+d"(y)); return y; } unsigned long long mrand49$state = 0x8a5cd789635d2dffULL; inline int mrand49() { mrand49$state *= 6364136223846793005ULL; mrand49$state += 1442695040888963407ULL; unsigned int ret = ((mrand49$state>>18)^mrand49$state) >> 27; unsigned int rot = (mrand49$state>>59); return (ret>>rot) | (ret<<-rot); } inline int lrand49(int r) { assert(1<=r); return asm_mul_hi(mrand49(), r); } inline double drand49() { return ((unsigned int)mrand49() + 0.5) * (1.0/4294967296.0); } struct SO { bool first; int turn; int use_turn; union choice { int i; double f; }; double best_score; std::vector best; choice change_value; void init() { use_turn = 0; best_score = -DBL_MAX; best.clear(); } void begin() { turn = 0; if(best.size()) { use_turn = lrand49(best.size()); } else { use_turn = 0; } if(best.size()<=use_turn) { use_turn = 0; } } int oracle(int n) { if(best.size() <= turn) { int ret = lrand49(n); best.emplace_back(); best.back().i = ret; if(turn==use_turn) { change_value = best.back(); } ++turn; return ret; } else if(turn!=use_turn) { return best[turn++].i; } else { ++turn; change_value.i = lrand49(n); return change_value.i; } } bool end(double score) { first = false; if(best_score < score) { best_score = score; best[use_turn] = change_value; return true; } return false; } }; SO so; const int MOD = 100000000; vector bottom; vector best_bottom; vector> target; int N; int max_error; int best_max_error; int W = 10000000; int halfW = W / 2; int sim() { bottom.resize(N); // 最下段の値 c[0..N-1] を乱数で生成 for (int i = 0; i < N; i++){ bottom[i] = (target[N-1][i] + so.oracle(W) - halfW + MOD) % MOD; } // ピラミッドを最下段から上へ再構築 vector> pyramid(N); pyramid[N - 1] = bottom; for (int i = N - 2; i >= 0; i--){ pyramid[i].resize(i + 1); for (int j = 0; j <= i; j++){ long long sum = static_cast(pyramid[i + 1][j]) + pyramid[i + 1][j + 1]; pyramid[i][j] = sum % MOD; } } // 各セルの誤差を計算し,その最大値を求める max_error = 0; for (int i = 0; i < N; i++){ for (int j = 0; j <= i; j++){ int diff = abs(pyramid[i][j] - target[i][j]); int err = min(diff, MOD - diff); max_error = max(max_error, err); } } // スコア計算 (5×10⁷ - 最大誤差) return 50000000 - max_error; } int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); cin >> N; // ターゲットのピラミッド値を三角形状に読み込む target.resize(N); for (int i = 0; i < N; i++){ target[i].resize(i + 1); for (int j = 0; j <= i; j++){ cin >> target[i][j]; } } int best_score = 0; for(int i=0; i<100; ++i) { so.begin(); int sc = sim(); if(so.end(sc)) { best_bottom = bottom; best_score = sc; best_max_error = max_error; } } // デバッグ用にシミュレーション結果を標準エラー出力へ cerr << "MaxError: " << best_max_error << "\n"; cerr << "Score: " << best_score << "\n"; // 最下段の値を出力 for (int i = 0; i < N; i++){ cout << best_bottom[i] << (i + 1 == N ? "\n" : " "); } return 0; }