2019-05-07 01:21:16 +00:00
# include <iostream>
2019-05-07 17:46:45 +00:00
# include <iomanip>
# include <algorithm>
# include <vector>
# include <string>
2019-05-07 01:21:16 +00:00
# include <cstring>
# include <cmath>
using namespace std ;
typedef long long ll ;
// DP Gimkit Solver
2019-05-07 01:59:05 +00:00
// Developed by Ta180m
2019-05-07 01:21:16 +00:00
2019-05-07 18:05:32 +00:00
// Initial conditions
2019-05-07 18:07:05 +00:00
// Change these values to alter the initial state
2019-05-07 21:23:09 +00:00
ll start = 0 , goal = 1e10 ; // Start and end amounts
2019-05-07 16:33:26 +00:00
int max_it = 150 ; // Number of iterations to solve
2019-05-07 18:05:32 +00:00
int MPQ = 0 , SB = 0 , M = 0 ; // Initial upgrade status
2022-04-29 15:48:17 +00:00
int D = 0 , R = 1 , B1 = 0 , B2 = 0 ; // Initial power-up status
2019-05-07 18:05:32 +00:00
2019-05-07 01:21:16 +00:00
// State: Iteration, Upgrade status, Power-up status
2019-05-07 21:23:09 +00:00
// DP array stores maximum possible money for each state
// pre array used to reconstruct optimal strategy
2019-05-07 16:33:26 +00:00
ll DP [ 7200000 ] , pre [ 7200000 ] ;
2019-05-07 01:21:16 +00:00
2019-05-07 16:33:26 +00:00
// Upgrade values
2019-05-07 01:21:16 +00:00
double val [ 3 ] [ 10 ] = {
{ 1 , 5 , 50 , 100 , 500 , 2000 , 5000 , 10000 , 250000 , 1000000 } ,
{ 2 , 20 , 100 , 200 , 1000 , 4000 , 10000 , 50000 , 1000000 , 5000000 } ,
{ 1 , 1.5 , 2 , 3 , 5 , 8 , 12 , 18 , 30 , 100 }
} ;
2019-05-07 16:33:26 +00:00
// Upgrade costs
2019-05-07 01:21:16 +00:00
ll cost [ 2 ] [ 3 ] [ 10 ] = {
{ { 0 , 10 , 100 , 1000 , 10000 , 75000 , 300000 , 1000000 , 10000000 , 100000000 } ,
{ 0 , 15 , 150 , 1500 , 15000 , 115000 , 450000 , 1500000 , 15000000 , 200000000 } ,
{ 0 , 50 , 300 , 2000 , 12000 , 85000 , 700000 , 6500000 , 65000000 , 1000000000 } } ,
{ { 0 , 8 , 75 , 750 , 7500 , 56250 , 225000 , 750000 , 7500000 , 75000000 } ,
{ 0 , 12 , 113 , 1125 , 11250 , 86250 , 337500 , 1125000 , 11250000 , 150000000 } ,
{ 0 , 38 , 225 , 1500 , 9000 , 63750 , 525000 , 4875000 , 48750000 , 750000000 } }
} ;
// Power-up costs
2019-05-07 16:33:26 +00:00
int base [ 4 ] = { 250 , 1000 , 20 , 50 } ;
double pcent [ 4 ] = { 0.16 , 0.30 , 0.03 , 0.06 } ;
ll pcost ( int i , ll x ) { return 5 * ceil ( ( double ) ( pcent [ i ] * x + base [ i ] ) / 5 ) ; }
2019-05-07 18:05:32 +00:00
// Utility function to format output
2019-05-07 17:46:45 +00:00
string format ( ll x ) {
string ret = to_string ( x ) ;
int pos = ret . length ( ) - 3 ;
while ( pos > 0 ) {
ret . insert ( pos , " , " ) ;
pos - = 3 ;
}
return ret ;
}
2019-05-07 01:21:16 +00:00
2019-05-07 18:05:32 +00:00
// Bottom-up DP algorithm
2019-05-07 01:21:16 +00:00
int main ( ) {
2019-05-07 18:05:32 +00:00
// Initialize DP array
2019-05-07 01:21:16 +00:00
memset ( DP , - 1 , sizeof ( DP ) ) ;
2019-05-07 16:33:26 +00:00
2019-05-07 21:23:09 +00:00
// Calculate initial state
int s = 3600 * MPQ + 360 * SB + 36 * M + 18 * D + 9 * R + 3 * B1 + B2 ;
2019-05-07 18:05:32 +00:00
// Set initial value
2019-05-07 17:46:45 +00:00
DP [ s ] = start ;
2019-05-08 13:35:43 +00:00
// Find the optimal solution
int sol = 7200000 ;
2019-05-07 16:33:26 +00:00
for ( int i = 0 ; i < 36000 * max_it ; i + + ) {
if ( DP [ i ] ! = - 1 ) {
2019-05-08 13:35:43 +00:00
if ( i / 36000 > sol / 36000 ) break ;
if ( DP [ i ] > = goal & & ( sol = = 7200000 | | DP [ i ] > DP [ sol ] ) ) sol = i ;
2019-05-07 18:05:32 +00:00
// Calculate parameters
2019-05-07 16:33:26 +00:00
int it = i / 36000 ;
int MPQ = ( i / 3600 ) % 10 , SB = ( i / 360 ) % 10 , M = ( i / 36 ) % 10 ;
int D = ( i / 18 ) % 2 , R = ( i / 9 ) % 2 , B1 = ( i / 3 ) % 3 , B2 = i % 3 ;
2019-05-07 18:05:32 +00:00
// Income per question
2019-05-07 16:33:26 +00:00
ll inc = round ( ( val [ 0 ] [ MPQ ] + ( i ! = 0 ? val [ 1 ] [ SB ] : 0 ) ) * val [ 2 ] [ M ] ) ;
// Answer a question
if ( DP [ i ] + inc > DP [ i + 36000 ] ) {
DP [ i + 36000 ] = DP [ i ] + inc ;
pre [ i + 36000 ] = i ;
}
// Answer a question using the mini bonus
if ( B1 = = 1 & & DP [ i ] + 2 * inc > DP [ i + 36003 ] ) {
DP [ i + 36003 ] = DP [ i ] + 2 * inc ;
pre [ i + 36003 ] = i ;
}
// Answer a question using the mega bonus
if ( B2 = = 1 & & DP [ i ] + 5 * inc > DP [ i + 36001 ] ) {
DP [ i + 36001 ] = DP [ i ] + 5 * inc ;
pre [ i + 36001 ] = i ;
}
// Answer a question using both the mini bonus and the mega bonus
if ( B1 = = 1 & & B2 = = 1 & & DP [ i ] + 10 * inc > DP [ i + 36004 ] ) {
DP [ i + 36004 ] = DP [ i ] + 10 * inc ;
pre [ i + 36004 ] = i ;
}
// Upgrade money per question
for ( int j = MPQ + 1 ; j < 10 & & DP [ i ] > = cost [ D ] [ 0 ] [ j ] ; j + + ) {
if ( DP [ i ] - cost [ D ] [ 0 ] [ j ] > DP [ i + 3600 * ( j - MPQ ) ] ) {
DP [ i + 3600 * ( j - MPQ ) ] = DP [ i ] - cost [ D ] [ 0 ] [ j ] ;
pre [ i + 3600 * ( j - MPQ ) ] = i ;
2019-05-07 01:21:16 +00:00
}
}
2019-05-07 16:33:26 +00:00
// Upgrade streak bonus
for ( int j = SB + 1 ; j < 10 & & DP [ i ] > = cost [ D ] [ 1 ] [ j ] ; j + + ) {
if ( DP [ i ] - cost [ D ] [ 1 ] [ j ] > DP [ i + 360 * ( j - SB ) ] ) {
DP [ i + 360 * ( j - SB ) ] = DP [ i ] - cost [ D ] [ 1 ] [ j ] ;
pre [ i + 360 * ( j - SB ) ] = i ;
}
}
2019-05-07 18:41:46 +00:00
// Upgrade multiplier
2019-05-07 16:33:26 +00:00
for ( int j = M + 1 ; j < 10 & & DP [ i ] > = cost [ D ] [ 2 ] [ j ] ; j + + ) {
if ( DP [ i ] - cost [ D ] [ 2 ] [ j ] > DP [ i + 36 * ( j - M ) ] ) {
DP [ i + 36 * ( j - M ) ] = DP [ i ] - cost [ D ] [ 2 ] [ j ] ;
pre [ i + 36 * ( j - M ) ] = i ;
2019-05-07 01:21:16 +00:00
}
}
2019-05-07 16:33:26 +00:00
// Buy the discounter
if ( D = = 0 & & DP [ i ] - pcost ( 0 , DP [ i ] ) > DP [ i + 18 ] ) {
DP [ i + 18 ] = DP [ i ] - pcost ( 0 , DP [ i ] ) ;
pre [ i + 18 ] = i ;
}
// Buy the rebooter
2019-05-17 18:11:22 +00:00
if ( R = = 0 & & DP [ i ] - pcost ( 1 , DP [ i ] ) > DP [ i - i % 36 + 9 ] ) {
DP [ i - i % 36 + 9 ] = DP [ i ] - pcost ( 1 , DP [ i ] ) ;
pre [ i - i % 36 + 9 ] = i ;
2019-05-07 16:33:26 +00:00
}
// Buy the mini bonus
if ( B1 = = 0 & & DP [ i ] - pcost ( 2 , DP [ i ] ) > DP [ i + 2 ] ) {
2019-05-07 21:23:09 +00:00
DP [ i + 3 ] = DP [ i ] - pcost ( 2 , DP [ i ] ) ;
pre [ i + 3 ] = i ;
2019-05-07 16:33:26 +00:00
}
// Buy the mega bonus
if ( B2 = = 0 & & DP [ i ] - pcost ( 3 , DP [ i ] ) > DP [ i + 1 ] ) {
DP [ i + 1 ] = DP [ i ] - pcost ( 3 , DP [ i ] ) ;
pre [ i + 1 ] = i ;
}
2019-05-07 01:21:16 +00:00
}
}
2019-05-07 18:05:32 +00:00
// Print output
2019-05-07 17:46:45 +00:00
if ( sol ! = 7200000 ) {
vector < int > output ;
for ( int i = sol ; i ! = s ; i = pre [ i ] ) output . push_back ( i ) ;
reverse ( output . begin ( ) , output . end ( ) ) ;
2019-05-08 13:49:21 +00:00
cout < < " Optimal strategy to reach $ " < < format ( goal ) < < " from $ " < < format ( start ) < < " in " < < sol / 36000 < < " iterations: " < < endl ;
2019-05-07 17:46:45 +00:00
for ( int i = 0 ; i < output . size ( ) ; i + + ) {
int it = output [ i ] / 36000 ;
int MPQ = ( output [ i ] / 3600 ) % 10 , SB = ( output [ i ] / 360 ) % 10 , M = ( output [ i ] / 36 ) % 10 ;
int D = ( output [ i ] / 18 ) % 2 , R = ( output [ i ] / 9 ) % 2 , B1 = ( output [ i ] / 3 ) % 3 , B2 = output [ i ] % 3 ;
2019-05-07 18:41:46 +00:00
// Output iteration
2019-05-07 17:46:45 +00:00
if ( it ! = output [ i - 1 ] / 36000 ) cout < < right < < setw ( 3 ) < < it < < " . " ;
else cout < < " " ;
2019-05-07 18:41:46 +00:00
// Answer a question
if ( it ! = output [ i - 1 ] / 36000 & & B1 = = ( output [ i - 1 ] / 3 ) % 3 & & B2 = = output [ i - 1 ] % 3 ) {
cout < < " Answer 1 question, bringing your total up to $ " < < format ( DP [ output [ i ] ] ) < < endl ;
}
// Answer a question with the mini bonus
else if ( it ! = output [ i - 1 ] / 36000 & & B1 ! = ( output [ i - 1 ] / 3 ) % 3 & & B2 = = output [ i - 1 ] % 3 ) {
cout < < " Answer 1 question using the mini bonus, bringing your total up to $ " < < format ( DP [ output [ i ] ] ) < < endl ;
}
// Answer a question using the mega bonus
else if ( it ! = output [ i - 1 ] / 36000 & & B1 = = ( output [ i - 1 ] / 3 ) % 3 & & B2 ! = output [ i - 1 ] % 3 ) {
cout < < " Answer 1 question using the mega bonus, bringing your total up to $ " < < format ( DP [ output [ i ] ] ) < < endl ;
}
// Answer a question using both the mini and mega bonuses
else if ( it ! = output [ i - 1 ] / 36000 & & B1 ! = ( output [ i - 1 ] / 3 ) % 3 & & B2 ! = output [ i - 1 ] % 3 ) {
cout < < " Answer 1 question using both the mini and mega bonuses, bringing your total up to $ " < < format ( DP [ output [ i ] ] ) < < endl ;
}
// Upgrade money per question
else if ( MPQ ! = ( output [ i - 1 ] / 3600 ) % 10 ) {
2019-05-18 17:38:20 +00:00
cout < < " Buy the Level " < < MPQ + 1 < < " ($ " < < format ( val [ 0 ] [ MPQ ] ) < < " ) money per question upgrade for $ " < < format ( cost [ D ] [ 0 ] [ MPQ ] ) < < " , making your total $ " < < format ( DP [ output [ i ] ] ) < < endl ;
2019-05-07 18:41:46 +00:00
}
// Upgrade streak bonus
else if ( SB ! = ( output [ i - 1 ] / 360 ) % 10 ) {
2019-05-18 17:38:20 +00:00
cout < < " Buy the Level " < < SB + 1 < < " ($ " < < format ( val [ 1 ] [ SB ] ) < < " ) streak bonus upgrade for $ " < < format ( cost [ D ] [ 1 ] [ SB ] ) < < " , making your total $ " < < format ( DP [ output [ i ] ] ) < < endl ;
2019-05-07 18:41:46 +00:00
}
// Upgrade multiplier
else if ( M ! = ( output [ i - 1 ] / 36 ) % 10 ) {
2019-05-18 17:38:20 +00:00
cout < < " Buy the Level " < < M + 1 < < " (x " < < format ( val [ 2 ] [ M ] ) < < " ) multiplier for $ " < < format ( cost [ D ] [ 2 ] [ M ] ) < < " , making your total $ " < < format ( DP [ output [ i ] ] ) < < endl ;
2019-05-07 18:41:46 +00:00
}
// Buy the rebooter
else if ( R ! = ( output [ i - 1 ] / 9 ) % 2 ) {
cout < < " Buy and use the rebooter for $ " < < format ( pcost ( 1 , DP [ output [ i - 1 ] ] ) ) < < " , making your total $ " < < format ( DP [ output [ i ] ] ) < < endl ;
}
2019-05-17 18:11:22 +00:00
// Buy the discounter
else if ( D ! = ( output [ i - 1 ] / 18 ) % 2 ) {
cout < < " Buy and use the discounter for $ " < < format ( pcost ( 0 , DP [ output [ i - 1 ] ] ) ) < < " , making your total $ " < < format ( DP [ output [ i ] ] ) < < endl ;
}
2019-05-07 18:41:46 +00:00
// Buy the mini bonus
else if ( B1 ! = ( output [ i - 1 ] / 3 ) % 3 ) {
cout < < " Buy the mini bonus for $ " < < format ( pcost ( 2 , DP [ output [ i - 1 ] ] ) ) < < " , making your total $ " < < format ( DP [ output [ i ] ] ) < < endl ;
}
// Buy the mega bonus
else if ( B2 ! = output [ i - 1 ] % 3 ) {
cout < < " Buy the mega bonus for $ " < < format ( pcost ( 3 , DP [ output [ i - 1 ] ] ) ) < < " , making your total $ " < < format ( DP [ output [ i ] ] ) < < endl ;
}
// Error
2019-05-07 17:46:45 +00:00
else cout < < " Error: Something went wrong " < < endl ;
2019-05-07 01:21:16 +00:00
}
}
2019-05-08 13:49:21 +00:00
else cout < < " No strategy to reach $ " < < format ( goal ) < < " from $ " < < format ( start ) < < " in " < < max_it < < " iterations could be found " < < endl ;
2019-05-07 01:21:16 +00:00
}