Problem:
Score : 500 points

Problem Statement

We have a chocolate bar partitioned into H horizontal rows and W vertical columns of squares.

The square (i, j) at the i-th row from the top and the j-th column from the left is dark if S_{i,j} is 0, and white if S_{i,j} is 1.

We will cut the bar some number of times to divide it into some number of blocks. In each cut, we cut the whole bar by a line running along some boundaries of squares from end to end of the bar.

How many times do we need to cut the bar so that every block after the cuts has K or less white squares?

Constraints

1 \leq H \leq 10

1 \leq W \leq 1000

1 \leq K \leq H \times W

S_{i,j} is 0 or 1.

Input

Input is given from Standard Input in the following format:

H W K
S_{1,1}S_{1,2}...S_{1,W}
:
S_{H,1}S_{H,2}...S_{H,W}

Output

Print the number of minimum times the bar needs to be cut so that every block after the cuts has K or less white squares.

Sample Input 1

3 5 4
11100
10001
00111

Sample Output 1

2

For example, cutting between the 1-st and 2-nd rows and between the 3-rd and 4-th columns - as shown in the figure to the left - works.

Note that we cannot cut the bar in the ways shown in the two figures to the right.

Sample Input 2

3 5 8
11100
10001
00111

Sample Output 2

0

No cut is needed.

Sample Input 3

4 10 4
1110010010
1000101110
0011101001
1101000111

Sample Output 3

3

Solution in Java8 (OpenJDK 1.8.0) (judge verdict: Accepted)

import java.util.Arrays;
import java.util.Scanner;
import java.util.stream.IntStream;

/**
 * 解説どおりに作成したソースコード
 */
public class Main {

	/** 白チョコを表す文字 */
	private static final char WHITE = '1';

	public static void main(String[] args) {
		try (Scanner scanner = new Scanner(System.in)) {
			int h = scanner.nextInt(), w = scanner.nextInt();
			int k = scanner.nextInt();
			boolean[][] s = new boolean[h][w];
			IntStream.range(0, h).forEach(i -> {
				char[] cs = scanner.next().toCharArray();
				IntStream.range(0, cs.length).forEach(j -> s[i][j] = (cs[j] == WHITE));
			});
			System.out.println(IntStream.range(0, (1 << h)).map(i -> {
				// 白チョコの数を格納する配列
				int[] counts = new int[Integer.bitCount(i) + 1];
				int result = Integer.bitCount(i);
				for (int j = 0; j < w; j++) {
					int[] now = calcNow(i, h, s, j);
					if (!check(now, k)) {
						return Integer.MAX_VALUE;
					}
					calcSum(counts, now);
					if (!check(counts, k)) {
						counts = now;
						result++;
					}
				}
				return result;
			}).min().getAsInt());
		}
	}

	/**
	 * チョコのj列目の白チョコの個数の配列を計算
	 * 
	 * @param plan チョコを横に分割するプラン
	 * @param h    チョコの高さ
	 * @param s    チョコの配列
	 * @param j    チョコのj列目に対して計算
	 * @return チョコのj列目の白チョコの個数の配列
	 */
	private static int[] calcNow(final int plan, int h, boolean[][] s, int j) {
		int[] result = new int[Integer.bitCount(plan) + 1];
		Arrays.fill(result, 0);
		int index = 0;
		for (int i = 0; i < h; i++) {
			result[index] += (s[i][j]) ? 1 : 0;
			if (0 != ((1 << i) & plan)) {
				index++;
			}
		}
		return result;
	}

	/**
	 * 配列に最大値を超えたものが含まれないかを計算
	 * 
	 * @param array 配列
	 * @param k     チョコの最大値
	 * @return 配列に最大値を超えたものが含まれないか
	 */
	private static boolean check(int[] array, int k) {
		for (int a : array) {
			if (a > k) {
				return false;
			}
		}
		return true;
	}

	/**
	 * 現在のチョコ数配列を合計用チョコ数配列に加算する
	 * 
	 * @param counts 合計用チョコ数配列
	 * @param now    現在のチョコ数配列
	 */
	private static void calcSum(int[] counts, int[] now) {
		for (int i = 0; i < Math.min(counts.length, now.length); i++) {
			counts[i] += now[i];
		}
	}
}