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++14 (GCC 5.4.1) (judge verdict: Accepted)

#include <bits/stdc++.h>
#include <boost/multiprecision/cpp_int.hpp>
using namespace std;
using namespace boost::multiprecision;

# define REP(i,n) for (int i=0;i<(n);++i)
# define rep(i,a,b) for(int i=a;i<(b);++i)
# define all(v) v.begin(),v.end()
# define showVector(v) REP(i,v.size()){cout << (v[i]) << " ";} cout << endl;
template<class T> inline bool chmin(T &a, T b){ if(a > b) { a = b; return true;} return false;}
template<class T> inline bool chmax(T &a, T b){ if(a < b) { a = b; return true;} return false;}
typedef long long int ll;
typedef pair<ll,ll> P_ii;
typedef pair<double,double> P_dd;

template<class T>
using MaxHeap = std::priority_queue<T>;

template<class T>
using MinHeap = std::priority_queue<T, std::vector<T>, std::greater<T>>;

template<class T>
vector<T> make_vec(size_t a){
    return vector<T>(a);
}

template<class T, class... Ts>
auto make_vec(size_t a, Ts... ts){
  return vector<decltype(make_vec<T>(ts...))>(a, make_vec<T>(ts...));
}

template<typename T,typename V>
typename enable_if<is_class<T>::value==0>::type
fill_v(T &t,const V &v){t=v;}

template<typename T,typename V>
typename enable_if<is_class<T>::value!=0>::type
fill_v(T &t,const V &v){
  for(auto &e:t) fill_v(e,v);
}

int pop_count(int n){
  return __builtin_popcount(n);
}

int pop_count(ll n){
  return __builtin_popcountll(n);
}

ll gcd(ll a, ll b) {
    if(a < b) swap(a,b);
    
    if(b == 0) return a;
    return gcd(b, a % b);
}

ll lcm(ll a, ll b){
    ll g = gcd(a,b);
    return (a/g)*b;
}

// 素数判定 O(√n)
bool is_prime(int n){
    for(int i = 2; i * i <= n; i++){
        if(n % i == 0) return false;
    }
    return true;
}

// 約数列挙 O(√n)
vector<ll> divisor(ll n){
    vector<ll> res;
    for(ll i = 1; i * i <= n; i++){
        if(n % i == 0){
            res.push_back(i);
            if(i != n / i) res.push_back(n / i);
        }
    }
    return res;
}

template<typename T>
map<T, ll> prime_factorize(T x){
  map<T, ll> res;
  for(int i=2;i*i<=x;i++){
    while(x%i==0){
      x/=i;
      res[i]++;
    }
  }
  if(x!=1) res[x]++;
  return res;
}

// エラトステネスの篩
// return lp[i] := iの最小素因数(lp[i] == iならば素数)
vector<int> SieveOfEratosthenes(int N = 10000000){
  vector<int> lp(N + 1, 0);
  vector<int> pr;
  for (int i=2; i<=N; ++i) {
      if (lp[i] == 0) {
          lp[i] = i;
          pr.push_back(i);
      }
      for (int j=0; j<(int)pr.size() && pr[j]<=lp[i] && i*pr[j]<=N; ++j)
          lp[i * pr[j]] = pr[j];
  }
  return lp;
}


// auto mod int
// https://youtu.be/L8grWxBlIZ4?t=9858
// https://youtu.be/ERZuLAxZffQ?t=4807 : optimize
// https://youtu.be/8uowVvQ_-Mo?t=1329 : division
const int mod = 1000000007;
struct mint {
  ll x; // typedef long long ll;
  mint(ll x=0):x(x%mod){}
  mint& operator+=(const mint a) {
    if ((x += a.x) >= mod) x -= mod;
    return *this;
  }
  mint& operator-=(const mint a) {
    if ((x += mod-a.x) >= mod) x -= mod;
    return *this;
  }
  mint& operator*=(const mint a) {
    (x *= a.x) %= mod;
    return *this;
  }
  mint operator+(const mint a) const {
    mint res(*this);
    return res+=a;
  }
  mint operator-(const mint a) const {
    mint res(*this);
    return res-=a;
  }
  mint operator*(const mint a) const {
    mint res(*this);
    return res*=a;
  }
  mint pow(ll t) const {
    if (!t) return 1;
    mint a = pow(t>>1);
    a *= a;
    if (t&1) a *= *this;
    return a;
  }
 
  // for prime mod
  mint inv() const {
    return pow(mod-2);
  }
  mint& operator/=(const mint a) {
    return (*this) *= a.inv();
  }
  mint operator/(const mint a) const {
    mint res(*this);
    return res/=a;
  }
};

const int MOD = 1000000007;
const int inf=1e9+7;
const ll longinf=1LL<<60 ;

ll intceil(ll a, ll b){
    if(a < 0){
      a *= -1;
      b *= -1;
    }
    if(b >= 0) return (a + b - 1 ) / b;
    return a / b;
}

ll intfloor(ll a, ll b){
    if(a < 0){
      a *= -1;
      b *= -1;
    }
    if(b >= 0) return a / b;
    return (a - b + 1) / b;
}

void addM(ll &a, ll b) {
    a += b;
    if (a >= MOD) a -= MOD;
}

void mulM(ll &a, ll b) {
    a = ((a%MOD)*(b%MOD))%MOD ;
}

ll powM(ll a,ll b) {
    ll ret = 1;
    ll tmp = a;
    while(b>0) {
        if((b&1)==1) ret = (ret * tmp) % MOD;
        tmp = (tmp * tmp) % MOD;
        b = b >> 1;
    }
    return ret;
}

// mod. m での a の逆元 a^{-1} を計算する
ll modinv(ll a, ll m) {
    ll b = m, u = 1, v = 0;
    while (b) {
        ll t = a / b;
        a -= t * b; swap(a, b);
        u -= t * v; swap(u, v);
    }
    u %= m;
    if (u < 0) u += m;
    return u;
}

// ラングレンス圧縮
vector<pair<char, int>> rang_com(string s){
  vector<pair<char, int>> ret;
  string t = s;
  t.erase(unique(all(t)), t.end());
  int now = 0;
  int pre = 0;
  for(auto ct : t){
    while(now < s.size() && s[now] == ct) now++;
    if(ret.size() == 0){
      ret.push_back({ct, now});
    } else {
      ret.push_back({ct, now - pre});
    }
    pre = now;
  }
  return ret;
}

template<typename T>
struct BIT{
  int n;
  vector<T> bit;
  // 1-indexed
  // コンストラクタは(size, 初期値)
  BIT():n(-1){}
  BIT(int n_,T d):n(n_),bit(n_+1,d){}

  // [0, i]：閉区間
  T sum(int i){
    T s=bit[0];
    for(int x=i;x>0;x-=(x&-x))
      s+=bit[x];
    return s;
  }
  void add(int i,T a){
    if(i==0) return;
    for(int x=i;x<=n;x+=(x&-x))
      bit[x]+=a;
  }

  int lower_bound(int w){
    if(w<=0) return 0;
    int x=0,r=1;
    while(r<n) r<<=1;
    for(int k=r;k>0;k>>=1){
      if(x+k<=n&&bit[x+k]<w){
        w-=bit[x+k];
        x+=k;
      }
    }
    return x+1;
  }

  T sum0(int i){
    return sum(i+1);
  }
  void add0(int i,T a){
    add(i+1,a);
  }

  // [l, r) : 半開区間
  T query(int l,int r){
    return sum(r-1)-sum(l-1);
  }

  T query0(int l,int r){
    return sum(r)-sum(l);
  }
};

int main(void) {
  cin.tie(0);
  ios::sync_with_stdio(false);  

  int h, w, k;
  cin >> h >> w >> k;

  auto g = make_vec<ll>(h + 1, w + 1);
  fill_v(g, 0);
  REP(i, h) {
    string s;
    cin >> s;
    REP(j, w){
      if(s[j] == '1'){
        g[i+1][j+1] = 1;
      }
    }
  }

  REP(i, h + 1) REP(j, w) g[i][j+1] += g[i][j]; 
  REP(j, w + 1) REP(i, h) g[i+1][j] += g[i][j]; 

  ll ans = longinf;
  REP(mask, 1 << (h - 1)){
    vector<int> v;
    v.push_back(0);
    REP(i, (h - 1)){
      if(mask >> i & 1){
        v.push_back(i + 1);
      }
    }
    v.push_back(h);

    ll tmp = pop_count(mask);
    int l = 0;
    bool chk = true;
    for(int r = 1; r <= w; r++){
      for(int i = 1; i < v.size(); i++){
        ll cnt = g[v[i]][r] - g[v[i-1]][r] - g[v[i]][l] + g[v[i-1]][l];
        if(cnt > k){
          if(r - l == 1){
            chk = false;
            break;
          }
          tmp++;
          l = r - 1;
          break;
        }
      }
      if(!chk) break;
    }
    if(chk) chmin(ans, tmp);
  }
  cout << ans << endl;

  return 0;
}