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 C# (Mono 4.6.2.0) (judge verdict: Accepted)

using System;
using System.Linq;
using System.Collections.Generic;

namespace Contest
{
    class Program
    {
        static void Main(string[] args)
        {
            ABC159.E();
        }

        class ABC159
        {
            public static void A()
            {
                var N = Read.Int();
                var M = Read.Int();
                Console.WriteLine(N * (N - 1) / 2 + M * (M - 1) / 2);
            }
            public static void B()
            {
                var S = Read.Str();
                bool ok = B_Kaibun(S) && B_Kaibun(S.Substring(0, (S.Length - 1) / 2)) && B_Kaibun(S.Substring((S.Length + 1) / 2, (S.Length - 1) / 2));
                Console.WriteLine(ok ? "Yes" : "No");
            }
            static bool B_Kaibun(string str)
            {
                for(int i = 0; i < str.Length / 2; ++i)
                {
                    if (str[i] != str[str.Length - 1 - i]) { return false; }
                }
                return true;
            }
            public static void C()
            {
                var L = Read.Int();
                Console.WriteLine(1.0 * L * L * L / 27);
            }
            public static void D()
            {
                var N = Read.Int();
                var A = Read.IntN();

                Dictionary<int, int> dict = new Dictionary<int, int>();
                foreach(var a in A)
                {
                    if (!dict.ContainsKey(a)) { dict.Add(a, 0); }
                    dict[a]++;
                }
                long count = 0;
                foreach(var kvp in dict)
                {
                    long v = kvp.Value;
                    count += v * (v - 1) / 2;
                }
                for(int i = 0; i < N; ++i)
                {
                    Console.WriteLine(count - (dict[A[i]] - 1));
                }
            }
            public static void E()
            {
                var H = Read.Int();
                var W = Read.Int();
                var K = Read.Int();
                var S = new List<int[]>();
                for (int i = 0; i < H; ++i)
                {
                    var s = Read.Str();
                    S.Add(s.Select(c => c == '1' ? 1 : 0).ToArray());
                }

                int[,] ASum = new int[H + 1, W + 1];
                for(int i = 0; i < H; ++i)
                {
                    for(int j = 0; j < W; ++j)
                    {
                        ASum[i + 1, j + 1] = ASum[i + 1, j] + ASum[i, j + 1] - ASum[i, j] + S[i][j];
                    }
                }
                int min = 1000000000;
                for(int i = 0; i < (1 << (H - 1)); ++i)
                {
                    Dictionary<int, int> pair = new Dictionary<int, int>();
                    int start = 0;
                    while (start < H)
                    {
                        int end = start + 1;
                        while (end < H && (i & (1 << (end - 1))) > 0)
                        {
                            end++;
                        }
                        pair.Add(start, end);
                        start = end;
                    }

                    int count = pair.Count - 2;
                    List<int> rights = new List<int>();
                    int left = 0;
                    while (left < W)
                    {
                        int right = left;
                        while (right < W && E_OK(ASum, pair, left, right+1, K))
                        {
                            right++;
                        }
                        if(left == right)
                        {
                            count = 1000000000;
                            break;
                        }
                        left = right;
                        rights.Add(right);
                        count++;
                    }
                    //if (min > count) { Console.WriteLine("{0} {1} {2}",i,count,String.Join("/",rights)); }
                    min = Math.Min(min, count);
                }
                Console.WriteLine(min);
            }
            static bool E_OK(int[,] Asum, Dictionary<int,int> pair, int startW, int endW, int K)
            {
                foreach(var kvp in pair)
                {
                    if (E_Count(Asum, kvp.Key, kvp.Value, startW, endW) > K) { return false; }
                }
                return true;
            }
            static int E_Count(int[,] Asum, int startH, int endH, int startW,int endW)
            {
                //Console.WriteLine("{0} {1} {2} {3} {4}",startH,endH,startW,endW, Asum[endH + 0, endW + 0] - Asum[startH, endW + 0] - Asum[endH + 0, startW] + Asum[startH, startW]);
                return Asum[endH + 0, endW + 0] - Asum[startH, endW + 0] - Asum[endH + 0, startW] + Asum[startH, startW];
            }
            public static void F()
            {
                var N = Read.Int();
                var S = Read.Int();
                var A = Read.IntN();

            }
        }

        class Util
        {
            public static readonly long P = 1000000007;

            public static T[,] Gen<T>(int r, int c, T v)
            {
                var matrix = new T[r, c];
                for (int i = 0; i < r; ++i)
                {
                    for (int j = 0; j < c; ++j)
                    {
                        matrix[i, j] = v;
                    }
                }
                return matrix;
            }

            public static long Sum(long[] array)
            {
                return Sum(array, array.Length);
            }
            public static long Sum(long[] array, int n)
            {
                long total = 0;
                for (int i = 0; i < n; ++i)
                {
                    total += array[i];
                }
                return total;
            }
            public static long Count(long[] array, long x)
            {
                return Count(array, x, array.Length);
            }
            public static long Count(long[] array, long x, int n)
            {
                long total = 0;
                for (int i = 0; i < n; ++i)
                {
                    total += (array[i] == x ? 1 : 0);
                }
                return total;
            }
            public static long[] ASum(long[] array)
            {
                var res = new long[array.Length + 1];
                for (int i = 0; i < array.Length; ++i)
                {
                    res[i + 1] = res[i] + array[i];
                }
                return res;
            }

            public static long GCD(long a, long b)
            {
                while (b > 0)
                {
                    var c = a % b;
                    a = b;
                    b = c;
                }
                return a;
            }
            public static bool IsPrime(long x)
            {
                var fact = Factorize(x);
                return fact.Count == 1 && fact.Values.ElementAt(0) == 1;
            }
            public static Dictionary<long, int> Factorize(long x)
            {
                var dict = new Dictionary<long, int>();
                long minp = 2;
                while (x > 1)
                {
                    bool ok = false;
                    for (long p = minp; p * p <= x; ++p)
                    {
                        if (x % p == 0)
                        {
                            if (!dict.ContainsKey(p))
                            {
                                dict.Add(p, 0);
                            }
                            dict[p]++;
                            minp = p;
                            x /= p;
                            ok = true;
                            break;
                        }
                    }
                    if (!ok)
                    {
                        if (!dict.ContainsKey(x)) { dict.Add(x, 0); }
                        dict[x]++;
                        break;
                    }
                }
                return dict;
            }
            public static HashSet<long> Divisor(long x)
            {
                var div = new HashSet<long>(); for (long p = 1; p * p <= x; ++p) { if (x % p == 0) { div.Add(p); } }
                foreach (var d in div.ToArray())
                {
                    if (!div.Contains(x / d)) { div.Add(x / d); }
                }
                return div;
            }
            public static long Inverse(long a, long p)
            {
                long b = p, c = 1, d = 0, e = 0, f = 0;
                while (b != 0)
                {
                    e = a / b;
                    f = b; b = a - e * b; a = f;
                    f = d; d = c - e * d; c = f;
                }
                c %= p;
                return c + (c < 0 ? p : 0);
            }
            public static long[] Facts(int n, long p)
            {
                var facts = new long[n + 1];
                facts[0] = 1;
                for (int i = 1; i <= n; ++i)
                {
                    facts[i] = (i * facts[i - 1]) % p;
                }
                return facts;
            }
            public static Func<int, int, long> Combin(int n, long P)
            {
                var fact = Facts(n, P);
                var inv = fact.Select(x => Inverse(x, P)).ToArray();
                return (N, M) =>
                {
                    if (N < 0 || N < M || M < 0) { return 0; }
                    return (((fact[N] * inv[M]) % P) * inv[N - M]) % P;
                };
            }
            public static Func<int, int, long> CombinLarge(int mMax, long p)
            {
                var inv = Enumerable.Range(0, mMax + 1).Select(x => Util.Inverse(x, Util.P)).ToArray();
                return (n, m) =>
                {
                    long mult = 1;
                    for (int i = 1; i <= m; ++i)
                    {
                        mult = (((mult * (n + 1 - i)) % Util.P) * inv[i]) % Util.P;
                    }
                    return mult;
                };
            }

            public static long[] MatMul(long[,] a, long[] b, long P)
            {
                var N = a.GetLength(0);
                var M = a.GetLength(1);
                var c = new long[N];
                for (int i = 0; i < N; ++i)
                {
                    for (int j = 0; j < M; ++j)
                    {
                        c[i] = (c[i] + a[i, j] * b[j]) % P;
                    }
                }
                return c;
            }

            public static long Power2(long n, long p)
            {
                return Power(2, n, p);
            }
            public static long Power(long a, long n, long p)
            {
                long res = 1;
                long mult = a;
                for (int i = 0; i < 40; ++i)
                {
                    if ((n & ((long)1 << i)) > 0)
                    {
                        res = (res * mult) % p;
                    }
                    mult = (mult * mult) % p;
                }
                return res;
            }
            public class MyDict<T1, T2> : Dictionary<T1, T2>
            {
                public new T2 this[T1 key]
                {
                    get { if (!base.ContainsKey(key)) { base.Add(key, default(T2)); } return base[key]; }
                    set { base[key] = value; }
                }
            }
            public static long CountInversion_Naive(int[] array)
            {
                var min = array.Min();
                var max = array.Max();
                var bit = new BIT(max - min + 1);
                long count = 0;
                for (int i = 0; i < array.Length; ++i)
                {
                    var v = array[i] - min + 1;
                    bit.Add(v, 1);
                    count += i + 1 - bit.Sum(v);
                }
                return count;
            }
            public class BIT
            {
                int N; long[] array;
                public BIT(int m) { for (int n = 1; ; n *= 2) { if (n >= m) { N = n; array = new long[N + 1]; break; } } }
                public void Add(int idx, int v) { for (int x = idx; x <= N; x += x & -x) { array[x] += v; } }
                public long Sum(int idx) { long ret = 0; for (int x = idx; x > 0; x -= x & -x) { ret += array[x]; } return ret; }
            }
            public class BST<T> where T : IComparable
            {
                public class Node
                {
                    public T V;
                    public Node L, R;
                    public int Count;
                    public Node(T v) { V = v; Count = 1; }
                }
                static Random _rnd = new Random();
                public static int Count(Node t) { return t == null ? 0 : t.Count; }
                static Node Update(Node t) { t.Count = Count(t.L) + Count(t.R) + 1; return t; }
                public static Node Merge(Node l, Node r)
                {
                    if (l == null || r == null) return l == null ? r : l;
                    if ((double)Count(l) / (double)(Count(l) + Count(r)) > _rnd.NextDouble())
                    { l.R = Merge(l.R, r); return Update(l); }
                    else { r.L = Merge(l, r.L); return Update(r); }
                }
                public static Tuple<Node, Node> Split(Node t, int k)
                {
                    if (t == null) return new Tuple<Node, Node>(null, null);
                    if (k <= Count(t.L))
                    {
                        var s = Split(t.L, k);
                        t.L = s.Item2;
                        return new Tuple<Node, Node>(s.Item1, Update(t));
                    }
                    else
                    {
                        var s = Split(t.R, k - Count(t.L) - 1);
                        t.R = s.Item1;
                        return new Tuple<Node, Node>(Update(t), s.Item2);
                    }
                }
                public static Node Remove(Node t, T v)
                {
                    if (Find(t, v) == null) return t;
                    return RemoveAt(t, LowerBound(t, v));
                }
                public static Node RemoveAt(Node t, int k)
                {
                    var s = Split(t, k);
                    var s2 = Split(s.Item2, 1);
                    return Merge(s.Item1, s2.Item2);
                }
                public static bool Contains(Node t, T v) { return Find(t, v) != null; }
                public static Node Find(Node t, T v)
                {
                    while (t != null)
                    {
                        var cmp = t.V.CompareTo(v);
                        if (cmp > 0) t = t.L;
                        else if (cmp < 0) t = t.R;
                        else break;
                    }
                    return t;
                }

                public static Node FindByIndex(Node t, int idx)
                {
                    if (t == null) return null;
                    var currentIdx = Count(t) - Count(t.R) - 1;
                    while (t != null)
                    {
                        if (currentIdx == idx) return t;
                        if (currentIdx > idx)
                        { t = t.L; currentIdx -= (Count(t == null ? null : t.R) + 1); }
                        else { t = t.R; currentIdx += (Count(t == null ? null : t.L) + 1); }
                    }
                    return null;
                }
                public static int UpperBound(Node t, T v)
                {
                    var torg = t;
                    if (t == null) return -1;

                    var ret = Int32.MaxValue;
                    var idx = Count(t) - Count(t.R) - 1;
                    while (t != null)
                    {
                        var cmp = t.V.CompareTo(v);

                        if (cmp > 0)
                        {
                            ret = Math.Min(ret, idx);
                            t = t.L;
                            idx -= (Count(t == null ? null : t.R) + 1);
                        }
                        else if (cmp <= 0)
                        {
                            t = t.R;
                            idx += (Count(t == null ? null : t.L) + 1);
                        }
                    }
                    return ret == Int32.MaxValue ? Count(torg) : ret;
                }
                public static int LowerBound(Node t, T v)
                {
                    var torg = t;
                    if (t == null) return -1;

                    var idx = Count(t) - Count(t.R) - 1;
                    var ret = Int32.MaxValue;
                    while (t != null)
                    {
                        var cmp = t.V.CompareTo(v);
                        if (cmp >= 0)
                        {
                            if (cmp == 0) ret = Math.Min(ret, idx);
                            t = t.L;
                            if (t == null) ret = Math.Min(ret, idx);
                            idx -= t == null ? 0 : (Count(t.R) + 1);
                        }
                        else if (cmp < 0)
                        {
                            t = t.R;
                            idx += (Count(t == null ? null : t.L) + 1);
                            if (t == null) return idx;
                        }
                    }
                    return ret == Int32.MaxValue ? Count(torg) : ret;
                }
                public static Node Insert(Node t, T v)
                {
                    var ub = LowerBound(t, v);
                    return InsertByIdx(t, ub, v);
                }
                static Node InsertByIdx(Node t, int k, T v)
                {
                    var s = Split(t, k);
                    return Merge(Merge(s.Item1, new Node(v)), s.Item2);
                }
                public static IEnumerable<T> Enumerate(Node t)
                {
                    var ret = new List<T>();
                    Enumerate(t, ret);
                    return ret;
                }
                static void Enumerate(Node t, List<T> ret)
                {
                    if (t == null) return;
                    Enumerate(t.L, ret);
                    ret.Add(t.V);
                    Enumerate(t.R, ret);
                }
            }
            public class Set<T> where T : IComparable
            {
                protected BST<T>.Node _root;
                public T this[int idx] { get { return ElementAt(idx); } }
                public int Count() { return BST<T>.Count(_root); }
                public virtual void Insert(T v)
                {
                    if (_root == null) _root = new BST<T>.Node(v);
                    else
                    {
                        if (BST<T>.Find(_root, v) != null) return;
                        _root = BST<T>.Insert(_root, v);
                    }
                }
                public void Clear() { _root = null; }
                public void Remove(T v) { _root = BST<T>.Remove(_root, v); }
                public bool Contains(T v) { return BST<T>.Contains(_root, v); }
                public T ElementAt(int k)
                {
                    var node = BST<T>.FindByIndex(_root, k);
                    if (node == null) throw new IndexOutOfRangeException();
                    return node.V;
                }
                public int Count(T v) { return BST<T>.UpperBound(_root, v) - BST<T>.LowerBound(_root, v); }
                public int LowerBound(T v) { return BST<T>.LowerBound(_root, v); }
                public int UpperBound(T v) { return BST<T>.UpperBound(_root, v); }
                public Tuple<int, int> EqualRange(T v)
                {
                    if (!Contains(v)) return new Tuple<int, int>(-1, -1);
                    return new Tuple<int, int>(BST<T>.LowerBound(_root, v), BST<T>.UpperBound(_root, v) - 1);
                }
                public List<T> ToList() { return new List<T>(BST<T>.Enumerate(_root)); }
            }
            public class MultiSet<T> : Set<T> where T : IComparable { public override void Insert(T v) { if (_root == null) { _root = new BST<T>.Node(v); } else { _root = BST<T>.Insert(_root, v); } } }

            public class UnionFindTree
            { //各Treeのサイズを保持する拡張仕様
                int[] parent;
                int[] count;
                public UnionFindTree(int n) { parent = new int[n]; count = new int[n]; for (int i = 0; i < n; ++i) { parent[i] = i; count[i] = 1; } }
                public int Root(int i) { if (parent[i] == i) { return i; } else { return parent[i] = Root(parent[i]); } }
                public int Count(int i) { return count[Root(i)]; }
                public bool Same(int i, int j) { return Root(i) == Root(j); }
                public void Unite(int i, int j) { var ri = Root(i); var rj = Root(j); if (ri != rj) { parent[ri] = rj; count[rj] += count[ri]; } }
            }
        }


        static class Read
        {
            static Queue<string> queue = new Queue<string>();
            static void Enqueue() { var ss = Console.ReadLine().Split(' '); foreach (var s in ss) { queue.Enqueue(s); } }
            public static int Int() { if (queue.Count == 0) { Enqueue(); } return Convert.ToInt32(queue.Dequeue()); }
            public static long Long() { if (queue.Count == 0) { Enqueue(); } return Convert.ToInt64(queue.Dequeue()); }
            public static string Str() { if (queue.Count == 0) { Enqueue(); } return queue.Dequeue(); }
            public static int[] IntN() { return Console.ReadLine().Split(' ').Select(s => Convert.ToInt32(s)).ToArray(); }
            public static long[] LongN() { return Console.ReadLine().Split(' ').Select(s => Convert.ToInt64(s)).ToArray(); }
            public static string[] StrN() { return Console.ReadLine().Split(' '); }
            public static Tuple<int, int>[] TupleInt(int n) { List<Tuple<int, int>> list = new List<Tuple<int, int>>(); for (int i = 0; i < n; ++i) { var ab = Read.IntN(); list.Add(new Tuple<int, int>(ab[0], ab[1])); } return list.ToArray(); }
            public static Tuple<long, long>[] TupleLong(int n) { List<Tuple<long, long>> list = new List<Tuple<long, long>>(); for (int i = 0; i < n; ++i) { var ab = Read.LongN(); list.Add(new Tuple<long, long>(ab[0], ab[1])); } return list.ToArray(); }
            public static Tuple<string, string>[] TupleStr(int n) { List<Tuple<string, string>> list = new List<Tuple<string, string>>(); for (int i = 0; i < n; ++i) { var ab = Read.StrN(); list.Add(new Tuple<string, string>(ab[0], ab[1])); } return list.ToArray(); }
            public static Tuple<double, double>[] TupleDouble(int n) { List<Tuple<double, double>> list = new List<Tuple<double, double>>(); for (int i = 0; i < n; ++i) { var ab = Read.LongN(); list.Add(new Tuple<double, double>(ab[0], ab[1])); } return list.ToArray(); }
            public static long[,] LongMatrix(int r, int c)
            {
                var mat = new long[r, c];
                for (int i = 0; i < r; ++i)
                {
                    var x = Read.LongN();
                    for (int j = 0; j < c; ++j)
                    {
                        mat[i, j] = x[j];
                    }
                }
                return mat;
            }
            public static Dictionary<int, HashSet<int>> AdjacencyList(int N, int M)
            {
                Dictionary<int, HashSet<int>> dict = new Dictionary<int, HashSet<int>>();
                for (int i = 0; i <= N; ++i)
                {
                    dict.Add(i, new HashSet<int>());
                }
                for (int i = 0; i < M; ++i)
                {
                    var ab = Read.IntN();
                    dict[ab[0]].Add(ab[1]);
                    dict[ab[1]].Add(ab[0]);
                }
                return dict;
            }
            public static Dictionary<int, Dictionary<int, long>> AdjacencyListWithWeight(int N, int M)
            {
                Dictionary<int, Dictionary<int, long>> dict = new Dictionary<int, Dictionary<int, long>>();
                for (int i = 0; i <= N; ++i)
                {
                    dict.Add(i, new Dictionary<int, long>());
                }
                for (int i = 0; i < M; ++i)
                {
                    var ab = Read.IntN();
                    dict[ab[0]].Add(ab[1], ab[2]);
                    dict[ab[1]].Add(ab[0], ab[2]);
                }
                return dict;
            }
        }
    }
}