C++11
Further small update: Do much less adding, and try all numbers of form A*B+C. I believe that, within the time limit, this is fairly close to optimal, assuming you only use +
, *
and !
. I leave other operators to people with more time than me!
Small update: Try harder to make use of factorials and numbers like 11....111. Also fixed bug that I wasn't counting !
in my costing
New result:
Primary Score = 3,810,660
Secondary Score = 12/09/2016 20:00
2532 1
s, 1505 operators.
Various tricks put together. My program starts by setting the shortest program for all factorials and numbers of the form 111..111 (I don't think this falls foul of the hard-wiring rule, as these are the shortest ways to make these numbers. I could rearrange my code so I check these patterns in my dynamic programming if you want). Then do a partial dynamic programming approach, trying various forms:
- A + B
- A*B + C
- A! + B
- 11....11 + B
Unfortunately I can't try all the ways of decomposing a number, so I choose for factorial and 11...11 to only try the nearest number, for A+B to try things near A/2, and for A*B+C to try only quite small As.
It would be easy to extend this to try some '-'s, by trying to overshoot slightly sometimes (particular in A*B - C), but I quite like only trying to grow.
Also, it is very hard to optimise the optimisation condition (I don't like it!) because in principle you can't come up with a 'best' value for each number in isolation, you have to consider your set of answers globally (which I don't intend to do).
Warning: This program needs a 64-bit machine, and around 10GB of memory (as I inefficiently make a giant array for all partially-computed results).
Program:
#include <algorithm>
#include <vector>
#include <string>
#include <assert.h>
#include <iostream>
#include <cmath>
std::vector<int> numints;
std::vector<int> numops;
std::vector<std::string> strings;
void fill_all_ones(long maxval)
{
int val = 1;
int len = 1;
std::string name = "1";
while(val < maxval) {
val = val * 10 + 1;
len++;
name = name + "1";
numints[val] = len;
strings[val] = name;
}
}
void get_best_for_next_full(long i);
// let's just assume this is the best way to make factorials
void fill_all_factorials(long maxval)
{
// skip 1 and 2
long result = 6;
long val = 3;
while(result < maxval) {
get_best_for_next_full(val);
strings[result] = "(" + strings[val] + ")!";
numints[result] = numints[val];
numops[result] = numops[val] + 1;
val++;
result = result * val;
}
}
long get_nearest_all_ones(long i)
{
int val = 11;
int prevval = 1;
while(val < i) {
prevval = val;
val = val * 10 + 1;
}
return prevval;
}
long get_nearest_factorial(long i)
{
int val = 6;
int prevval = 2;
int step = 3;
while(val < i) {
prevval = val;
step++;
val = val * step;
}
return prevval;
}
int getlen(long i);
void get_best_for_next_full(long i)
{
if(numints[i] > 0)
return;
int best = INT_MAX; // we'll do better than this
std::string beststring = "invalid2";
int ones = -1;
int ops = -1;
for(long loop = 1; loop <= i/2; loop++)
{
int new_val = getlen(loop) + getlen(i - loop);
if(new_val < best) {
best = new_val;
ones = numints[loop] + numints[i - loop];
beststring = "(" + strings[loop] + "+" + strings[i - loop] + ")";
ops = numops[loop] + numops[i - loop] + 1;
}
}
for(long loop = 2; loop * loop <= i; loop++)
{
long divisor = i / loop;
long rem = i - loop*divisor;
assert(rem >= 0);
int new_val;
if(rem == 0)
{
new_val = getlen(divisor) + getlen(loop);
}
else
{
new_val = getlen(divisor) + getlen(rem) + getlen(loop);
}
if(new_val < best) {
best = new_val;
if(rem == 0) {
ones = numints[divisor] + numints[loop];
beststring = "(" + strings[divisor] + "*" + strings[loop] + ")";
ops = numops[divisor] + numops[loop] + 1;
} else {
ones = numints[divisor] + numints[loop] + numints[rem];
beststring = "(" + strings[divisor] + "*" + strings[loop] + "+" + strings[rem] + ")";
ops = numops[divisor] + numops[loop] + numops[rem] + 2;
}
}
}
numints[i] = ones;
strings[i] = beststring;
numops[i] = ops;
}
void check_divising(const long i, const long loop, long& best, long& ones, std::string& beststring, long& ops);
void check_adding(const long i, const long loop, long& best, long& ones, std::string& beststring, long& ops);
void get_best_for_next_partial(long i)
{
if(numints[i] > 0)
return;
long best = INT_MAX; // we'll do better than this
long ones = 1;
std::string beststring = "invalid";
long ops = 1;
// Special: Try a nearby all ones
{
long loop = get_nearest_all_ones(i);
check_adding(i, loop, best, ones, beststring, ops);
}
// Special: Try nearest factorial
{
long loop = get_nearest_factorial(i);
check_adding(i, loop, best, ones, beststring, ops);
}
for(long loop = 2; loop * loop <= i; loop++)
{
check_divising(i, loop, best, ones, beststring, ops);
}
numints[i] = ones;
strings[i] = beststring;
numops[i] = ops;
}
void check_adding(const long i, const long loop, long& best, long& ones, std::string& beststring, long& ops)
{
int new_val = getlen(loop) + getlen(i - loop);
if(new_val < best) {
best = new_val;
ones = numints[loop] + numints[i - loop];
beststring = "(" + strings[loop] + "+" + strings[i - loop] + ")";
ops = numops[loop] + numops[i - loop] + 1;
}
}
void check_divising(const long i, const long loop, long& best, long& ones, std::string& beststring, long& ops)
{
long divisor = i / loop;
long rem = i - loop*divisor;
assert(rem >= 0);
int new_val;
if(rem == 0)
{
new_val = getlen(divisor) + getlen(loop);
}
else
{
new_val = getlen(divisor) + getlen(rem) + getlen(loop);
}
if(new_val < best) {
best = new_val;
if(rem == 0) {
ones = numints[divisor] + numints[loop];
beststring = "(" + strings[divisor] + "*" + strings[loop] + ")";
ops = numops[divisor] + numops[loop] + 1;
}
else {
ones = numints[divisor] + numints[loop] + numints[rem];
beststring = "(" + strings[divisor] + "*" + strings[loop] + "+" + strings[rem] + ")";
ops = numops[divisor] + numops[loop] + numops[rem] + 2;
}
}
}
long count = 0;
long countops = 0;
const int little_cutoff = 200000;
int getlen(long i)
{
if(numints[i] == 0) {
if(i < little_cutoff)
get_best_for_next_full(i);
else
get_best_for_next_partial(i);
}
if(numints[i] == 0) {
std::cout << i << " failure!" << numops[i] << ":" << strings[i] << std::endl;
exit(1);
}
return numints[i] + numops[i];
}
const std::vector<long> vals = {945536, 16878234, 32608778, 42017515, 48950830, 51483452, 52970263, 54278649, 63636656, 78817406, 89918907, 90757642, 95364861, 102706605, 113965374, 122448605, 126594161, 148064959, 150735075, 154382918, 172057472, 192280850, 194713795, 207721209, 220946392, 225230299, 227043979, 241011012, 248906099, 249796314, 250546528, 258452706, 276862988, 277140688, 280158490, 286074562, 308946627, 310972897, 322612091, 324445400, 336060042, 346729632, 349428326, 352769482, 363039453, 363851029, 392168304, 401975104, 407890409, 407971913, 425780757, 459441559, 465592122, 475898732, 482826596, 484263150, 506235403, 548951531, 554295842, 580536366, 587051904, 588265985, 588298051, 590968352, 601194306, 607771869, 618578932, 626776380, 667919873, 681786366, 689854904, 692055400, 697665495, 711608194, 734027104, 750869335, 757710567, 759967747, 777616154, 830071127, 833809927, 835873060, 836438554, 836945593, 863728236, 864158514, 871273503, 881615667, 891619600, 897181691, 918159061, 920521050, 924502226, 929983535, 943162304, 950210939, 950214176, 962610357, 974842859, 988572832};
const long biggest = 988572832;
int main(void)
{
numints.push_back(2);
strings.push_back("(1-1)");
numops.push_back(1);
numints.push_back(1);
strings.push_back("1");
numops.push_back(0);
numints.push_back(2);
strings.push_back("(1+1)");
numops.push_back(1);
numints.resize(biggest + 1);
strings.resize(biggest + 1);
numops.resize(biggest + 1);
fill_all_ones(biggest);
fill_all_factorials(biggest);
for(long i = 0; i < little_cutoff; ++i)
get_best_for_next_full(i);
for(long v : vals) {
get_best_for_next_partial(v);
std::cout << v << ":" << strings[v] << "\n";
count += numints[v];
countops += numops[v];
}
std::cout << count << ":" << countops << ":" << count * countops << "\n";
}
Results:
945536:((1111*(1+(11+11))+(1+1))*((1+11)*(1+(1+1))+1)+1)
16878234:(((1+(1+1111))*(1+(1+(1+111)))+(11+11))*((1+11)*11+1)+(1+1))
32608778:((((((1+(1+1)))!+(111+11111))*(11*11)+111)*(1+11)+1)*(1+1))
42017515:((11)!+((((1+111)*11)*11+1)*((1+11)*(1+11)+11)))
48950830:((((11+11)*(1+11))+(11111*(1+(1+1))))*((1+111)*(1+(1+11))+1)+1)
51483452:(((1+(1+1111))*(1+111)+1)*(11+(((1+11)*11+(1+1))*(1+(1+1))))+111)
52970263:((11+((1111*11+(1+(1+1)))*(1+(1+1))))*(111*(1+(1+11))+1)+11)
54278649:((11)!+(((1+(11+(11+(11+1111))))*111+1)*(1+(1+111))+1))
63636656:((((11+111)*(1+(1+1)))*(1+111)+11)*(1+(111+((((1+(1+1)))!)!*(1+1)))))
78817406:(((((111*(11+11)+1)*(1+1))*(1+111)+111)*(1+11)+1)*(1+11)+(1+1))
89918907:(((111+((1+(1+((1+(1+1)))!)))!)*(1+1))*(1+1111)+((11*11)*(1+(1+1))))
90757642:((1111+((11+11111)*(1+1)))*(111*(11+((1+(1+(1+1))))!)+1)+(1+111))
95364861:((11)!+(((((((11+11)*11)+11111)*111)*11+(1+1))*(1+1))*(1+1)+1))
102706605:(((11)!+(((111+((11*11)*11))*(1+(((1+(1+1)))!)!))*11))*(1+1)+1)
113965374:((((111*(1+(1+(1+11))))*1111+((1+(11+11))*11+1))*11+1)*((1+(1+1)))!)
122448605:(((((1+(1+1)))!)!+((111*11)*11))*((1+(((1+(1+1)))!)!)*(1+11)+1)+(1+1))
126594161:(((((11*11)+(((1+(1+1)))!)!)*(1+111))*(1+11)+1)*(1+111)+1)
148064959:((11)!+(((111*111+(1+11))*111+1)*((1+(1+11))*((1+(1+1)))!+1)+(1+(1+1))))
150735075:(((111*111+(1+1))*(1+1111)+(1+11))*11+(1+((1+(1+1)))!))
154382918:((1111*(1+11)+1)*(((1+(11+(111+111)))*(1+1))+11111)+111)
172057472:((((((1+11)*11)*11+1)*(1+(1+1)))+11111)*(11+11111)+((1+11)*11))
192280850:(((11111*(1+11)+11)*(1+(((1+(1+1)))!)!)+(11+111))*(1+1))
194713795:((11)!+((((111+11111)*(1+(1+(1+111)))+((1+(1+1)))!)*11)*11+1))
207721209:(((111*111)*(1+(11+11))+(1+1))*(1+(1+(11+(((1+(1+1)))!)!)))+(1+(1+(1+1))))
220946392:((11)!+((((1+(1+(1+1111)))*(11+111))*111+11)*(1+11)+(1+(1+(1+1)))))
225230299:((111111111+((111*111+(1+((1+(1+1)))!))*(11+111)+(11+11)))*(1+1)+1)
227043979:((((((11+11)*11)+11111)*(1+(1+1))+1)*1111+(1+(1+1)))*((1+(1+1)))!+1)
241011012:(((11)!+((11)!+((11)!+((11+1111)*((1+111)*((1+(1+1)))!+1)))))*(1+1))
248906099:(((11111+(((((1+(1+1)))!)!*111)*(1+1)))*(1+111)+111)*(1+(1+11)))
249796314:(((11)!+(((((1+(1+1)))!)!+((1+1111)*(1+11)))*(11+111)+111))*((1+(1+1)))!)
250546528:((11)!+(((111*111)*(1+(1+(1+11)))+11)*(111*11)+(1+(11+1111))))
258452706:(((11)!+(((((1+(1+1)))!)!*((1+(1+1)))!+1)*(11+(((1+(1+1)))!)!)))*((1+(1+1)))!)
276862988:(((11+(1111*(1+1)))*(((1+(1+1)))!+1111))*111+(((1+(1+1)))!+11))
277140688:(((111*111+(1+(1+(1+(1+11)))))*(1+1))*(11+(111+11111))+(1+111))
280158490:((11)!+(((1+(111+111111))*(((1+(1+1)))!)!+(1+(1+1)))*(1+(1+1))+1))
286074562:(((11)!+((((11+1111)*(11+11))*(1+1)+1)*(1+(11+1111))))*(1+(1+1))+1)
308946627:((11)!+((((1+1111)*(((1+(1+1)))!)!+((11+11)*(1+1)))*(1+111)+1)*(1+(1+1))))
310972897:((11111*(1+(1+1))+1)*(((1111+(111*11))*(1+1))*(1+1)+1)+11)
322612091:((((((1+11)*(1+11))*(1+11)+(1+1))*111+1)*(1+111))*(1+(1+(1+(1+11))))+11)
324445400:(((1111111+(1+(1+1)))*(1+1))*((1+11)*(1+11)+(1+1))+(1+111))
336060042:(((1+1111)*(1+(11+111))+(1+111))*(11+((111*11+1)*(1+1)))+(1+1))
346729632:(((1+(1+(11111+(111*111))))*((1+111)*11+1)+(1+(1+(1+11))))*(1+11))
349428326:(((((11+11)*11)*11+1)*(1+1111)+1)*(1+(((1+(1+1)))!+111)))
352769482:(((1+11111)*(111*(11+11))+((11+111)*((1+1)*(1+1)+1)))*(1+(1+11)))
363039453:(((((1+111)*(1+111)+1)*(1+1))*(1+(1+11))+11)*(1+(1+1111)))
363851029:((((111*11+1)*1111+11)*((1+11)*11+(1+1))+(1+11))*(1+1)+1)
392168304:(((((1+(1+1111))*(1+111))*11+1)*(1+(1+11))+11)*(11+11))
401975104:(((((1+11)*(1+11)+1)*111)*111+11)*((1+111)*(1+1)+1)+(1+(1+(1+1))))
407890409:(((1+11111)*11)*((1+1111)*(1+(1+1))+1)+((1+1111)*(1+1)+1))
407971913:((11)!+((11)!+(((1+(1+11111))*(1+1)+1)*(((11+111)*11)*11+1)+(1+1111))))
425780757:(((1111+((((1+11)*11)+11111)*(1+(1+1))))*11+1)*1111+((1+(1+1)))!)
459441559:(((11111+(((1+(1+111))*(1+1)+1)*111))*111+1)*(1+(1+(1+111)))+(1+(1+11)))
465592122:(((11)!+((((1111*(11*(1+(1+1))+1)+1)*(1+(11+11)))*(1+1)+1)*111))*(1+1))
475898732:(((11)!+(((((1+111)*11+(1+1))*(1+11))*(1+1)+1)*(1+(1+111))))*11+1)
482826596:(((1+(((111*11)*11)+(11111*(1+1))))*111+1)*(11+111)+((1+(1+1)))!)
484263150:(((111*111+(1+(1+1)))*111+11)*(1+(111+((11+11)*11))))
506235403:(((1+11))!+((((1+(1+1111))*(1+1111)+((11+111)*(1+1)))*11+1)*(1+1)+1))
548951531:((((111+111)*(1+1)+1)*111+11)*11111+((11+111)*(1+11)+1))
554295842:(((1+11))!+((((1+1111)*111+1)*((1+1)*(1+1)+1))*(11+111)+(1+111)))
580536366:(((1+(111+((111*111+11)*(1+11))))*(1+111)+1)*(11+((1+(1+(1+1))))!)+11)
587051904:(((((1+1111)*(1+11))*(1+(1+1))+1)*(111*11+1)+(111*((1+(1+1)))!))*(1+11))
588265985:(((1+11))!+((1+(111+(1111*(1+(1+11)))))*((1+111)*(11*((1+(1+1)))!+1)+(1+(1+1)))))
588298051:((((((11+111)*11)*11)+(11111*(1+(1+1))))*(1+1111)+1)*11)
590968352:(((((((1+(1+1)))!)!+11111)*111+(11+11))*((1+111)*(1+1)+1)+1)*(1+1))
601194306:((((1111*(1+(1+(1+(11+111))))+1)*111+(1+1))*(1+(1+1))+1)*(1+(1+11))+11)
607771869:(((1+11))!+(((11)!+(((1111*11+1)*(1+1))*(1+(11+111))+11))*(1+(1+1))))
618578932:(((((1111*111)*11+1)*(1+1)+1)*(1+1))*(1+(1+(1+111)))+(1+111))
626776380:((((1+(1+(1+1))))!+((((1+(1+1)))!)!+(1111*111)))*(1+(11+((1+((1+(1+1)))!))!)))
667919873:((((((1+(11+111))*11+1)*111+(1+(1+1)))*1111+1)*(1+1))*(1+1)+1)
681786366:(((1+11))!+((11)!+(((11)!+((11)!+((1+(1+11111))*((1+11)*(1+11))+111)))*(1+1))))
689854904:(((11+((11111+((1+1111)*11))*(1+1)))*((11+111)*11+1)+11)*11+(1+1))
692055400:(((1+11))!+(((((1+(1+111))*(1+(1+(1+11))))*11)*11+1)*(1+(1+1111))+1))
697665495:(((1+11))!+(((((((1+(1+1)))!)!*(1+(1+(1+111)))+1)*(1+11))*(1+1)+1)*111))
711608194:(((11)!+(((1+(1+(1+(1+1111))))*(11+((11+111)*(1+1)))+(1+1))*1111))*(1+1))
734027104:(((111*(11+((1+(1+(1+1))))!)+1)*(((1+(1+1)))!+11)+1)*11111+1111)
750869335:((11111111+((1+(((1+(1+1)))!)!)*((1+11)*11+1)+1))*(11*((1+(1+1)))!+1))
757710567:((((((11+111)*11)+111111)*(1+(1+1))+1)*(1+(11+1111))+(1+(1+1)))*(1+1)+1)
759967747:(((11)!+(((1+(1+(111+11111)))*(1+(1+111)))*(1+(11+11))+1))*11)
777616154:((11111*(111+(((111*11+1)*(1+1))*(1+1)))+(11+111))*(1+(1+(1+11))))
830071127:((((1+111)*111)*((1+(1+1)))!+1)*(((1+(1+1)))!+(11+11111))+(111*(1+1)+1))
833809927:((((11+1111)*(1+1)+1)*111+1)*(1+(1+(11+(1111*(1+(1+1))))))+111)
835873060:(((((11+(111+111))*111+1)*(1+(1+111))+1)*(1+(1+11))+1)*(11+11))
836438554:(((1+11))!+(((11111*(1+1)+1)*((11+(((1+(1+1)))!)!)*11+1)+1111)*(1+1)))
836945593:(((1111*1111+(1+111))*(1+(1+111))+(1+(1+1)))*((1+(1+1)))!+1)
863728236:(((1+(1111+((11+11111)*(1+1))))*(111*111+((1+(1+1)))!))*(1+(1+1)))
864158514:(((1+11))!+(((1111*(1+(1+(1+11)))+((1+(1+1)))!)*111+1)*(111*(1+1)+1)+11))
871273503:((((1+11111)*(11+11)+1)*((1+(1+11))*(1+1)+1)+1)*((1+11)*11)+111)
881615667:((11111+((111*111+11)*(1+1)))*((111*111)*(1+1)+1)+((11+1111)*11))
891619600:(((11)!+((11)!+((((1+(11+11))*(1+1))+111111)*11)))*11+(1+(1+1)))
897181691:((11+(11+(11+((1+(1+((1+(1+1)))!)))!)))*(11+(11111*(1+1)))+((111*11+1)*11))
918159061:(((11)!+(((11+11)*11+1)*(1+(1+11))))*(1+(11+11))+(1+(1+(1+1))))
920521050:(((11)!+((((1+(11+1111))*(1+(1+(1+1111))))*(1+111)+111)*(1+(1+1))))*(1+1))
924502226:((((1111*(1+11))*(1+1)+1)*((111*(1+11)+1)*(1+1)+1))*(1+(1+11))+11)
929983535:(((11)!+((((11+111)*111+1)*111)*((1+11)*(1+1)+1)+(1+1)))*(1+11)+11)
943162304:(((11)!+((((((1+((1+(1+1)))!))!+(111*111))*111+(1+1))*(1+111))*(1+1)))*(1+1))
950210939:(((11+(111+11111))*(1+(1+(1+(((1+(1+1)))!)!)))+(1+1))*(((1+(1+1)))!+111)+(1+1))
950214176:(((11)!+((((111*111)*(1+(1+11)))*11+1)*((1+(11+111))*(1+1)+1)))*(1+1))
962610357:((((1+11))!+((1+((((1+(1+1)))!)!+(111*(1+11))))*(11+1111)+(1+111)))*(1+1)+1)
974842859:((((((11*(1+((1+(1+1)))!))+1111)*11+1)*(1+111))*((1+(1+1)))!)*111+11)
988572832:(((111111111+((11111*(1+(1+1111))+11)*11+(1+(1+1))))*(1+1))*(1+1))