#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

/* 数の上限 */
#define MAX_NUM (long long int)(1e8)

/* 実験回数 */
#define MAX_TRIAL 20

/* 関数のプロトタイプ宣言 */
long long int triangle(long long int);
int is_triangle(long long int);
int is_sum_of_three_triangles(long long int n, int *list);
void fill_list(int *list);

int main(){
  long long int i;
  int ct,k,j,k1,k2;

  srand((unsigned)time(NULL));

  /* 2つ以下の三角数の和で表せるかどうかのリストを作成する */
  int *list = (int*)calloc(MAX_NUM, sizeof(int));
  fill_list(list);

  for(ct=0; ct<MAX_TRIAL; ct++){
    i = rand()%1000000+1;
    /* nが3つ以下の三角数の和で表せるかを確認 */
    if(k=is_sum_of_three_triangles(i, list)){
    if (k==-1) { // 2個の三角数の和
                k1=is_triangle(i-triangle(list[i]));
        printf("%lld = (%d*(%d+1)/2) +  (%d*(%d+1)/2)\n",i, list[i], list[i], k1,k1);
        }
    else{ // 3個の三角数の和
        k1 = list[i-triangle(k)];
        k2 = is_triangle(i-triangle(k)-triangle(k1));
        printf("%lld = (%d*(%d+1)/2) +  (%d*(%d+1)/2) +  (%d*(%d+1)/2)\n",i, k,k, k1,k1, k2,k2);
      }
      fflush(stdout);
    } else{
      printf("\r%lld NG\n", i);
      return 0;
    }
  }

  free(list);
  return 0;
}

/* nが三角数かどうかを返す関数 */
/* 三角数なら1，そうでないなら0を返す */
int is_triangle(long long int n){
  /* i(i+1)/2=n　を解くと，i=-1/2+sqrt(1/4+2n) */
  long long int i = sqrt(0.25+2*n)-0.5;
  if(triangle(i) == n) return i;
  return 0;
}

long long int power(int a, int n){
  long long int ret = 1;
  int i;
  for(i=0; i<n; i++) ret *= a;
  return ret;
}


/* n番目の三角数を返す関数 */
/* n番目の三角数は，n(n+1)/2 で表される */
long long int triangle(long long int n){
 return n*(n+1)/2;
}

/* 2つ以下の三角数の和で表せるかどうかのリストを作成する */
/* iが2つ以下の三角数の和で表せるとき1，そうでないとき0とする */
/* 0を三角数とみなすと，ちょうど2つの三角数の和で表せることと等価 */
void fill_list(int* list){
  long long int i,j;
  long long int t1,t2;

  for(i=0; i < MAX_NUM; i++) list[i] = 0;

  /* t1<=t2 の下で総当り */
  for(i=0; (t1=triangle(i)) < MAX_NUM/2; i++){
    for(j=i; (t2=triangle(j)) < (MAX_NUM-t1); j++){
      list[t1+t2] = i;
    }
  }
}

/* nが3つ以下の三角数の和で表せるかどうかを返す関数 */
/* 表せるなら1，そうでないなら0を返す */
/* 2つ以下の三角数の和で表せるかどうかのリストを利用する */
int is_sum_of_three_triangles(long long int n, int *list){

  /* 2つ以下の和で表せるなら条件を満たす */
  if(list[n]) return -1; // -1を返すのは２つの三角数の和のとき

  long long int i, t;
  /* nから三角数を引いた数が2つ以下の三角数の和で表すことができればよい */
  for(i=1; (t=triangle(i)) <= n/3; i++){
    if(list[n-t]) return i; //3つの三角数の和のときはiを返す
  }
  return 0;
}
