// Arup Guha
// 4/11/2022
// Solution to 2022 Spring COP 3503 Program #6: Road Race
// Edited version of the original solution edited on 4/24/2022.
// This version charges no penalty for staying in the same lane.

import java.util.*;

public class roadracepath_v2 {
	
	// Toggle between 1 and 2 to get the output to the two different parts.
	final public static int PART = 1;

	final public static int LANE_CONST = 5;
	final public static int METERS_PER_KILOMETER = 1000;
	final public static int SECONDS_PER_HOUR = 3600;
	
	final public static double EPSILON = 1e-6;
	
	// This is 10 times the worst possible time.
	final public static int MAX_TIME = 1000000000;

	public static int numSegs;
	public static int numLanes;
	public static int[] distance;
	public static double[][] speed;
	
	public static void main(String[] args) {
	
		// Get basic parameters.
		Scanner stdin = new Scanner(System.in);
		numSegs = stdin.nextInt();
		numLanes = stdin.nextInt();
	
		// Get all segment distances.
		distance = new int[numSegs];
		for (int i=0; i<numSegs; i++)
			distance[i] = stdin.nextInt();
	
		// Get average speed on each segment in each lane. Convert to meters per second.
		speed = new double[numSegs][numLanes];
		for (int i=0; i<numSegs; i++)
			for (int j=0; j<numLanes; j++)
				speed[i][j] = 1.0*stdin.nextInt()*METERS_PER_KILOMETER/SECONDS_PER_HOUR;
				
		// next[i][j] will store next lane to go to, to achieve best time from lane j in segment i.
		// The last column of this array will be ignored.
		int[][] next = new int[numSegs][numLanes];
		for (int i=0; i<numSegs; i++) Arrays.fill(next[i], -1);
		
		// dp[i][j] will store the fastest time, "going backwards" that we complete segment i ending in lane j.
		double[][] dp = new double[numSegs][numLanes];
		
		// Initialize the "last segment" to be the travel time of that segment.
		for (int i=0; i<numLanes; i++)
			dp[numSegs-1][i] = distance[numSegs-1]/speed[numSegs-1][i];
		
		// Do the segments in reverse order, so we can build the lexicographically first solution.
		for (int i=numSegs-2; i>=0; i--) {
		
			// Lanes can be in any order.
			for (int j=0; j<numLanes; j++) {
			
				// Ensures we overwrite this.
				dp[i][j] = MAX_TIME;
			
				// k is the lane we are "coming from" in backwards order. (ie the lane we will take in segment i+1)
				// We must go through these in forward order so we can build the lexicographically first solution.
				for (int k=0; k<numLanes; k++) {
				
					/*** This is the change in version 2 --> no cost if we stay in the same lane!!! ***/
					int tAdded = 0;
					if (j != k) tAdded = (j-k)*(j-k) + LANE_CONST;
					
					// Time for driving the segment.
					double dTime = distance[i]/speed[i][j];
					
					// Our time is the best time to get to segment i+1 on lane k, plus the time to change lanes,
					// plus the time to drive this segment.
					double thisTime = dp[i+1][k] + tAdded + dTime;
					
					// We only update if this time is strictly better.
					if (thisTime < dp[i][j]-EPSILON) {
						dp[i][j] = thisTime;
						next[i][j] = k;
					}
				} // end k.
			} // end j
		} // end i.
	
		// Set the first lane to be the best.
		int lane = 0;
		double bestTime = dp[0][0];
		
		// See if anything is strictly better.
		for (int i=1; i<numLanes; i++) {
		
			// Time to update.
			if (dp[0][i] < bestTime) {
				lane = i;
				bestTime = dp[0][i];
			}
		}
		
		// Best time.
		if (PART == 1)
			System.out.printf("%.2f\n", bestTime);
		
		// Path.
		else {
			System.out.print((lane+1)+" ");
			for (int i=0; i<numSegs-1; i++) {
				System.out.print((next[i][lane]+1)+" ");
				lane = next[i][lane];
			}
			System.out.println();
		}		
	}
}