import java.util.*;

// Extension 1: For giggles you should try to do a build back!
// Extension 2: Try finding the maximum number of operations!

public class mcm 
{
    // Stores the dimensions for the matrix
    public static int[][] dim;
    
    // Store the index for the rows and column
    public static final int ROW_IND = 0;
    public static final int COL_IND = 1;
    
    // A value representing infinity
    public static final int oo = 987654321;
    
    // The sentinel value
    public static final int SENT = -1;
    
    // Our memo table
    public static int[][] memo;
    
    // ------------------------------------
    //            Main Method
    // ------------------------------------
    public static void main(String[] Args) 
    {
        Scanner sc = new Scanner(System.in);
        
        // Read in the number of matrices
        int n = sc.nextInt();
        
        // Initialize the memory for storing the matrix
        dim = new int[2][n];
        
        // Initialize and fill the memo
        memo = new int[n][n];
        for (int[] tmp : memo)
            Arrays.fill(tmp, SENT);
        
        // Read in the dimensions of the matrices
        for (int i = 0; i < n; i++) 
        {
            dim[ROW_IND][i] = sc.nextInt();
            dim[COL_IND][i] = sc.nextInt();
        }
        
        // Use a recursive DP
        System.out.println(dp(0, n - 1));
        
        // Use a recursive Greedy
        System.out.println(greedy(0, n - 1));
    }
    
    // ------------------------------------
    //            DP Solution
    // ------------------------------------
    public static int dp(int start, int end) 
    {
        // Base case a single matrix has no operations
        if (start == end) 
        {
            return 0;
        }
        
        // Comment this conditional to make this a divide and conquer
        if (memo[start][end] != SENT)
            return memo[start][end];
        
        // Have a maximum (large) value for the answer initially
        int ans = oo;
        
        // the variable "i" will store the last element of our "divide" (e.g. (A B C) (D E) i = C)
        for (int i = start; i < end; i++) 
        {
            // Determine the number of operations taken for each partition
            int x = dp(start, i);
            int y = dp(i + 1, end);
            
            // Determining the number of operations taken for the final multiplication
            int curOp = dim[ROW_IND][start] * dim[COL_IND][i] * dim[COL_IND][end];
            
            // Compute the total number of operations
            int totalOp = curOp + x + y;
            
            // Check if the current total is better than the current answer
            if (ans > totalOp)
                ans = totalOp;
        }
        
        // Comment this to assignment to make this a divide and conquer
        memo[start][end] = ans;
        
        // return the answer
        return ans;
    }
    
    // ------------------------------------
    //           Greedy Attempt
    // ------------------------------------
    public static int greedy(int start, int end) 
    {
        // Check if we are multiplying together a single matrix
        if (start == end) 
        {
            return 0;
        }
        
        // Store the number of operations
        int smallestCurOp = oo;
        
        // Store the index of the "best" multiplication
        int index = -1;
        
        // Greedily find the smallest number of operations
        // the variable "i" will store the last element of our "divide" (e.g. (A B C) (D E) i = C)
        for (int i = start; i < end; i++) 
        {
            // Compute the number of operations
            int curOp = dim[ROW_IND][start] * dim[COL_IND][i] * dim[COL_IND][end];
            
            // Check if this is a smaller number of operations than the current smallest
            if (curOp < smallestCurOp) 
            {
                // Update
                smallestCurOp = curOp;
                index = i;
            }
        }
        
        // Find the answer recursively
        // This step here was wrong in class it is now fixed!
        int x = greedy(start, index);
        int y = greedy(index + 1, end);
        
        // Compute the number of operations
        int curOp = dim[ROW_IND][start] * dim[COL_IND][index] * dim[COL_IND][end];
        
        // Return the found answer
        return x + y + curOp;
    }
}