結果
| 問題 |
No.5021 Addition Pyramid
|
| コンテスト | |
| ユーザー |
colun
|
| 提出日時 | 2025-03-21 15:47:28 |
| 言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 1,903 ms / 2,000 ms |
| コード長 | 6,800 bytes |
| コンパイル時間 | 1,628 ms |
| コンパイル使用メモリ | 107,872 KB |
| 実行使用メモリ | 5,888 KB |
| スコア | 50,893,337 |
| 最終ジャッジ日時 | 2025-03-21 15:49:10 |
| 合計ジャッジ時間 | 100,249 ms |
|
ジャッジサーバーID (参考情報) |
judge2 / judge5 |
| 純コード判定しない問題か言語 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 50 |
ソースコード
#include <iostream>
#include <vector>
#include <random>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <cfloat>
#include <cassert>
#include <sys/time.h>
using namespace std;
inline void getCpuClock(unsigned long long & t) {
#if __emscripten__
t = std::chrono::high_resolution_clock::now().time_since_epoch().count();
#else
__asm__ __volatile__ ("rdtsc" : "=a"(*(unsigned int*)&t), "=d"(((unsigned int*)&t)[1]));
#endif
}
inline unsigned long long getCpuClock() {
unsigned long long t;
getCpuClock(t);
return t;
}
inline double getNativeTime() {
timeval tv;
gettimeofday(&tv, 0);
return tv.tv_sec + tv.tv_usec * 1e-6;
}
unsigned long long getTime$initCpuClock;
unsigned long long getTime$reserveUpdateCpuClock;
double getTime$initNativeTime;
double getTime$secPerClock;
double getTime$doneTime;
inline void initTime() {
getTime$initNativeTime = getNativeTime();
getCpuClock(getTime$initCpuClock);
getTime$secPerClock = 0.00000000025;
getTime$reserveUpdateCpuClock = 10000000;
getTime$doneTime = 0;
}
struct getTime$init_class {
inline getTime$init_class() {
initTime();
}
};
getTime$init_class getTime$init_obj;
#if __local__
double getTime$revRate = 1.0;
double getTime$rate = 1.0;
bool getTime$stopFlag = false;
double getTime$correct = 0.0;
#endif
#if __local__
inline void setLocalTimeRate(double rate) {
getTime$rate = rate;
getTime$revRate = 1.0 / rate;
}
#else
#define setLocalTimeRate(...)
#endif
inline double getTime() {
#if __local__
if(getTime$stopFlag) {
return getTime$doneTime;
}
#endif
unsigned long long now;
getCpuClock(now);
now -= getTime$initCpuClock;
if(getTime$reserveUpdateCpuClock < now) {
double nowTime = getNativeTime() - getTime$initNativeTime;
getTime$secPerClock = nowTime / now;
getTime$reserveUpdateCpuClock = now + (unsigned long long)(0.05 * now / nowTime);
}
#if __local__
return (getTime$doneTime = std::fmax(getTime$doneTime, getTime$secPerClock * now * getTime$revRate + getTime$correct));
#else
return getTime$doneTime = std::fmax(getTime$doneTime, getTime$secPerClock * now);
#endif
}
inline void getTimeStop() {
#if __local__
if(!getTime$stopFlag) {
getTime();
getTime$stopFlag = true;
}
#endif
}
inline void getTimeStart() {
#if __local__
if(getTime$stopFlag) {
double before = getTime();
getTime$stopFlag = false;
double after = getTime();
getTime$correct += before - after;
getTime$doneTime = before;
}
#endif
}
#if __local__
inline void setTime(double t) {
getTime$correct += t - getTime();
getTime$doneTime = t;
}
#else
#define setTime(...)
#endif
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<choice> 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<int> bottom;
vector<int> best_bottom;
vector<vector<int>> target;
int N;
int max_error;
int best_max_error;
int W = 5000000;
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<vector<int>> 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<long long>(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(){
initTime();
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;
so.init();
while(getTime() < 1.9) {
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;
}
colun