結果
| 問題 |
No.5018 Let's Make a Best-seller Book
|
| コンテスト | |
| ユーザー |
e869120
|
| 提出日時 | 2023-09-19 00:15:51 |
| 言語 | C++14 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
TLE
|
| 実行時間 | - |
| コード長 | 7,246 bytes |
| コンパイル時間 | 972 ms |
| コンパイル使用メモリ | 86,136 KB |
| 実行使用メモリ | 7,100 KB |
| スコア | 0 |
| 最終ジャッジ日時 | 2023-10-01 12:31:31 |
| 合計ジャッジ時間 | 4,567 ms |
|
ジャッジサーバーID (参考情報) |
judge13 / judge14 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | TLE * 2 -- * 98 |
ソースコード
#include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;
// =============================================================== デバッグ用の出力 ===============================================================
class DebugMode {
public:
int T = 52;
int N = 10;
int CurrentTurn;
int CurrentMoney;
int Score;
vector<int> Sales;
vector<int> Remain;
vector<int> Popula;
vector<double> D;
vector<vector<double>> Z;
double Randouble() {
double s = 1, t = 0;
for (int i = 0; i < 3; i++) {
s /= 1024.0;
t += 1.0 * (rand() % 1024) * s;
}
return t;
}
void Initialize() {
CurrentMoney = 2000000;
CurrentTurn = 0;
Score = 0;
Sales = vector<int>(N, 0);
Remain = vector<int>(N, 0);
Popula = vector<int>(N, 0);
D = vector<double>(N, 0);
Z = vector<vector<double>>(T, vector<double>(N, 0));
for (int i = 0; i < N; i++) D[i] = Randouble() * 1.0 + 0.5;
for (int i = 0; i < T; i++) {
for (int j = 0; j < N; j++) Z[i][j] = Randouble() * 0.5 + 0.75;
}
}
void Refresh() {
int i = CurrentTurn;
for (int j = 0; j < N; j++) Sales[j] = min(Remain[j], (int)(1.0 * pow(Remain[j], 0.5) * pow(1.05, Popula[j]) * D[j] * Z[i][j]));
for (int j = 0; j < N; j++) {
if (Remain[j] == 0) continue;
if (10 * Sales[j] >= 3 * Remain[j]) Popula[j] = min(+60, Popula[j] + 1);
if (10 * Sales[j] < 1 * Remain[j]) Popula[j] = max(-60, Popula[j] - 1);
}
for (int j = 0; j < N; j++) Score += Sales[j];
for (int j = 0; j < N; j++) CurrentMoney += 1000LL * Sales[j];
for (int j = 0; j < N; j++) Remain[j] -= Sales[j];
CurrentTurn += 1;
}
};
// =============================================================== デバッグ用の出力 ===============================================================
const int DEBUG = 1;
int T, N;
int Money;
int S[19], P[19], R[19];
vector<int> Ad_Record;
double Expected_D[19], Sum_D[19], Cnt_D[19];
DebugMode COMP;
void Initialize() {
T = 0; N = 0; Money = 0; Ad_Record = vector<int>{ 0, 0 };
for (int i = 0; i < 19; i++) {
Expected_D[i] = 0; Sum_D[i] = 0; Cnt_D[i] = 0;
S[i] = 0; P[i] = 0; R[i] = 0;
}
}
void Ask(int Type, vector<int> vec) {
if (DEBUG == 1) {
cout << Type;
for (int i = 0; i < vec.size(); i++) cout << " " << vec[i];
cout << endl;
}
if (DEBUG == 2 && Type == 1) {
for (int i = 0; i < N; i++) COMP.CurrentMoney -= 500 * vec[i];
for (int i = 0; i < N; i++) COMP.Remain[i] += vec[i];
}
if (DEBUG == 2 && Type == 2) {
COMP.CurrentMoney -= 500000 * (1 << (vec[0] - 1));
for (int i = 0; i < N; i++) COMP.Popula[i] = min(60, COMP.Popula[i] + vec[0]);
}
}
void Decide(int turn) {
bool AdFlag = false;
int count60 = 0;
for (int i = 1; i <= N; i++) {
if (P[i] == 60) count60 += 1;
}
// 広告を打つ条件
if (turn <= 15 && (Money >= 1100000 && turn - Ad_Record[Ad_Record.size() - 1] >= 2 && count60 <= 2)) AdFlag = true;
if (turn <= 25 && (Money >= 1200000 && turn - Ad_Record[Ad_Record.size() - 1] >= 2 && count60 <= 2)) AdFlag = true;
if (turn <= 60 && (Money >= 1300000 && turn - Ad_Record[Ad_Record.size() - 1] >= 2 && count60 <= 2)) AdFlag = true;
// 広告を打つ場合
if (AdFlag == true) {
Ask(2, vector<int>{2});
Ad_Record.push_back(turn);
}
// 広告を打たない場合 (最後の方 / 売上最大化を目指す)
else if (count60 >= 5) {
double cl = 0.0, cr = 10000.0, cm;
vector<int> L(N, 0);
for (int i = 0; i < 40; i++) {
cm = (cl + cr) / 2.0;
vector<int> vec(N, 0);
int sum = 0;
for (int j = 1; j <= N; j++) {
double keisuu = pow(1.05, P[j]) * Expected_D[j];
vec[j - 1] = (int)pow(keisuu / cm, 2.0);
sum += vec[j - 1];
}
if (500 * sum <= Money) { cr = cm; L = vec; }
else { cl = cm; }
}
Ask(1, L);
}
// 広告を打たない場合 (最後以外)
else {
vector<int> L(N, 0);
int NeedMoney = 0;
for (int i = 1; i <= N; i++) {
double keisuu = 0.0;
if (P[i] >= 50) keisuu = 15.0;
else if (P[i] >= 40) keisuu = 8.0;
else {
if (turn >= 20) keisuu = 5.5 + 0.07 * (turn - 20);
else keisuu = 3.0 + 0.1 * turn;
}
int Goal = keisuu * pow(pow(1.05, 1.0 * P[i]) * Expected_D[i], 2.0);
Goal = max(1, Goal - R[i]);
L[i - 1] = Goal;
NeedMoney += 500 * Goal;
}
if (NeedMoney > Money) {
for (int i = 1; i <= N; i++) L[i - 1] = (1LL * L[i - 1] * Money / NeedMoney);
}
Ask(1, L);
}
}
void Refresh_D() {
for (int i = 1; i <= N; i++) {
if (S[i] >= 1) {
int moto_popular = P[i];
if (10 * S[i] >= 3 * (S[i] + R[i])) moto_popular -= 1;
if (10 * S[i] < 1 * (S[i] + R[i])) moto_popular += 1;
double expected = (0.5 + S[i]) / (pow(1.0 * (S[i] + R[i]), 0.5) * pow(1.05, moto_popular));
double keisuu = 1.0 - 1.0 / S[i];
Sum_D[i] += keisuu * expected;
Cnt_D[i] += keisuu;
}
if (Cnt_D[i] < 0.01) Expected_D[i] = 0.6;
else Expected_D[i] = min(1.4, max(0.6, Sum_D[i] / Cnt_D[i]));
}
}
int main() {
// ========================================================================= 通常モード =========================================================================
if (DEBUG == 1) {
cin >> T >> N >> Money;
for (int i = 1; i <= N; i++) Expected_D[i] = 1.0;
// インタラクティブ開始
for (int t = 1; t <= T; t++) {
// (あ) 行動を決める
Decide(t);
// (い) 売上部数などを入力する
cin >> Money;
for (int i = 1; i <= N; i++) cin >> S[i];
for (int i = 1; i <= N; i++) cin >> P[i];
for (int i = 1; i <= N; i++) cin >> R[i];
cerr << "Turn = " << t << ":" << endl;
cerr << Money << endl;
for (int i = 1; i <= N; i++) cerr << S[i] << " "; cerr << endl;
for (int i = 1; i <= N; i++) cerr << P[i] << " "; cerr << endl;
for (int i = 1; i <= N; i++) cerr << R[i] << " "; cerr << endl;
cerr << endl;
// D の値を更新
Refresh_D();
}
}
// ========================================================================= デバッグモード =========================================================================
if (DEBUG == 2) {
int NumCases = 5000;
int ScoreSum = 0;
int ScoreCnt = 0;
for (int cases = 1; cases <= NumCases; cases++) {
Initialize();
T = 52; N = 10; Money = 2000000; COMP.Initialize();
for (int i = 1; i <= N; i++) Expected_D[i] = 1.0;
// インタラクティブ開始
for (int t = 1; t <= T; t++) {
// (あ) 行動を決める
Decide(t);
// (い) 売上部数などを入力する
COMP.Refresh();
Money = COMP.CurrentMoney;
for (int i = 1; i <= N; i++) S[i] = COMP.Sales[i - 1];
for (int i = 1; i <= N; i++) P[i] = COMP.Popula[i - 1];
for (int i = 1; i <= N; i++) R[i] = COMP.Remain[i - 1];
if (NumCases == 1) {
cerr << "Turn = " << t << ":" << endl;
cerr << Money << endl;
for (int i = 1; i <= N; i++) cerr << S[i] << " "; cerr << endl;
for (int i = 1; i <= N; i++) cerr << P[i] << " "; cerr << endl;
for (int i = 1; i <= N; i++) cerr << R[i] << " "; cerr << endl;
cerr << endl;
}
// D の値を更新
Refresh_D();
}
printf("Case#% 3d: Score =% 7d\n", cases, COMP.Score);
ScoreSum += COMP.Score;
ScoreCnt += 1;
}
printf("=======================================\n");
printf("Average Score =% 9d\n", ScoreSum / ScoreCnt);
}
return 0;
}
e869120