#!/usr/bin/env python3 n,w = [int(i) for i in input().split()] w += 1 words = [input() for i in range(n)] lengths = [len(word) for word in words] # Check if an amount of lines works def check_amount(a): DP = [0]*(w+1) DP_amounts = [0]*(w+1) DP_widths = [i-1 for i in range(w+1)] for i in range(w+1): c = DP[i] longest = 0 for j in range(c, min(c+a, n)): longest = max(longest, lengths[j]) new_width = i + 1 + longest if new_width > w: break if j + 1 > DP[new_width]: DP[new_width] = j+1 DP_widths[new_width] = longest DP_amounts[new_width] = j+1 - c return max(DP) == n, DP, DP_widths, DP_amounts # binary search on the correct amount of lines low, high = 0, n b, best_DP, best_widths, best_amounts = check_amount(high) while high - low > 1: mid = (high+low) // 2 b, DP, DP_widths, DP_amounts = check_amount(mid) if b: high = mid best_DP = DP best_widths = DP_widths best_amounts = DP_amounts else: low = mid # backtrack column widths widths = [] amounts = [] ww = best_DP.index(n) while ww>0: widths.append(best_widths[ww]) amounts.append(best_amounts[ww]) ww -= widths[-1]+1 # add words to proper columns split_words = [] for i,am in enumerate(amounts): split_words.append([]) for j in range(am): split_words[-1].append(words.pop().ljust(widths[i])) split_words[-1].reverse() while len(split_words[-1]) < high: split_words[-1].append(''.ljust(widths[i])) widths.reverse() split_words.reverse() # print output print(high, len(widths)) print(*widths) for i in range(high): line = ' '.join([split_words[j][i] for j in range(len(widths))]) print(line.rstrip())