You've got an *n* × *m* pixel picture. Each pixel can be white or black. Your task is to change the colors of as few pixels as possible to obtain a barcode picture.

A picture is a barcode if the following conditions are fulfilled: 
 -  All pixels in each column are of the same color. -  The width of each monochrome vertical line is at least *x* and at most *y* pixels. In other words, if we group all neighbouring columns of the pixels with equal color, the size of each group can not be less than *x* or greater than *y*.
The first line contains four space-separated integers *n*, *m*, *x* and *y* (1 ≤ *n*, *m*, *x*, *y* ≤ 1000; *x* ≤ *y*).

Then follow *n* lines, describing the original image. Each of these lines contains exactly *m* characters. Character "." represents a white pixel and "#" represents a black pixel. The picture description doesn't have any other characters besides "." and "#".
import math
import sys
from bisect import bisect_left,bisect_right
from collections import defaultdict as dd
from collections import deque, Counter
from heapq import heappop,heappush,heapify,merge
from itertools import permutations, accumulate, product
from math import gcd,sqrt,ceil
toBin=lambda x:bin(x).replace("0b","")
I=lambda:map(int,input().split())
inf=float("inf");DIRS=[[1,0],[-1,0],[0,1],[0,-1]];CHARS="abcdefghijklmnopqrstuvwxyz";MOD=10**9+7;
input=sys.stdin.readline

# Uncomment below to use comb
# fact=[1]*(300006)
# for i in range(2, 300006):fact[i]=((fact[i-1]*i)%MOD)
# def comb(n,r):return (fact[n]*pow(fact[r]*fact[n-r],MOD-2,MOD))%MOD if n>=r else 0

class UnionFind:
    def __init__(self,n):self.p=list(range(n));self.rank=[0]*n
    def find(self,x):
        if x!=self.p[x]:self.p[x]=self.find(self.p[x])
        return self.p[x]
    def union(self,x, y):
        px,py=self.find(x),self.find(y)
        if px==py:return 0
        self.p[py]=px
        self.rank[px]+=self.rank[py]
        return 1
class SegmentTree:
    def __init__(self,n,func):
        self.n=n;self.tree=[0]*2*self.n;self.func=func
    def query(self, l, r):
        l+=self.n;r+=self.n;ans=1#change
        while l<r:
            if l&1:ans=self.func(ans,self.tree[l]);l+=1
            if r&1:r-=1;ans=self.func(ans,self.tree[r])
            l>>=1;r>>=1
        return ans
    def update(self,i,val):
        i+=self.n;self.tree[i]=val
        while i>1:i>>=1;self.tree[i]=self.func(self.tree[i*2],self.tree[i*2+1])
class RangeQueue:
    def __init__(self,fn=min):
        self.inbox=[];self.outbox=[];self.fn=fn
    def mn(self,st):return st[-1][1] if st else 0 #gcd or max= or sum0,mi=inf
    def get_fn(self):return self.fn(self.mn(self.inbox),self.mn(self.outbox))
    def sz(self):return len(self.inbox)+len(self.outbox)
    def push(self,v):
        if not self.inbox:self.inbox.append((v,v))
        else:self.inbox.append((v,self.fn(v,self.mn(self.inbox))))
    def pop(self):
        if len(self.outbox)==0:self.shift()
        self.outbox.pop()
    def shift(self):
        while self.inbox:
            self.outbox.append((self.inbox[-1][0],self.fn(self.inbox[-1][0],self.mn(self.outbox))))
            self.inbox.pop()
_A=True
class SortedList:
    def __init__(A,iterable=[],_load=200):B=_load;C=sorted(iterable);A._len=E=len(C);A._load=B;A._lists=D=[C[A:A+B]for A in range(0,E,B)];A._list_lens=[len(A)for A in D];A._mins=[A[0]for A in D];A._fen_tree=[];A._rebuild=_A
    def _fen_build(B):
        B._fen_tree[:]=B._list_lens;C=B._fen_tree
        for A in range(len(C)):
            if A|A+1<len(C):C[A|A+1]+=C[A]
        B._rebuild=False
    def _fen_update(B,index,value):
        A=index
        if not B._rebuild:
            C=B._fen_tree
            while A<len(C):C[A]+=value;A|=A+1
    def _fen_query(B,end):
        A=end
        if B._rebuild:B._fen_build()
        D=B._fen_tree;C=0
        while A:C+=D[A-1];A&=A-1
        return C
    def _fen_findkth(A,k):
        B=A._list_lens
        if k<B[0]:return 0,k
        if k>=A._len-B[-1]:return len(B)-1,k+B[-1]-A._len
        if A._rebuild:A._fen_build()
        C=A._fen_tree;D=-1
        for F in reversed(range(len(C).bit_length())):
            E=D+(1<<F)
            if E<len(C)and k>=C[E]:D=E;k-=C[D]
        return D+1,k
    def _delete(B,pos,idx):
        A=pos;C=B._lists;E=B._mins;D=B._list_lens;B._len-=1;B._fen_update(A,-1);del C[A][idx];D[A]-=1
        if D[A]:E[A]=C[A][0]
        else:del C[A];del D[A];del E[A];B._rebuild=_A
    def _loc_left(E,value):
        F=value
        if not E._len:return 0,0
        G=E._lists;I=E._mins;B,A=-1,len(G)-1
        while B+1<A:
            C=B+A>>1
            if F<=I[C]:A=C
            else:B=C
        if A and F<=G[A-1][-1]:A-=1
        H=G[A];B,D=-1,len(H)
        while B+1<D:
            C=B+D>>1
            if F<=H[C]:D=C
            else:B=C
        return A,D
    def _loc_right(D,value):
        G=value
        if not D._len:return 0,0
        H=D._lists;J=D._mins;B,E=0,len(H)
        while B+1<E:
            A=B+E>>1
            if G<J[A]:E=A
            else:B=A
        I=H[B];F,C=-1,len(I)
        while F+1<C:
            A=F+C>>1
            if G<I[A]:C=A
            else:F=A
        return B,C
    def add(A,value):
        E=value;C=A._load;F=A._lists;H=A._mins;G=A._list_lens;A._len+=1
        if F:
            B,I=A._loc_right(E);A._fen_update(B,1);D=F[B];D.insert(I,E);G[B]+=1;H[B]=D[0]
            if C+C<len(D):F.insert(B+1,D[C:]);G.insert(B+1,len(D)-C);H.insert(B+1,D[C]);G[B]=C;del D[C:];A._rebuild=_A
        else:F.append([E]);H.append(E);G.append(1);A._rebuild=_A
    def discard(A,value):
        C=value;D=A._lists
        if D:
            E,B=A._loc_right(C)
            if B and D[E][B-1]==C:A._delete(E,B-1)
    def remove(A,value):
        B=value;C=A._len;A.discard(B)
        if C==A._len:raise ValueError('{0!r} not in list'.format(B))
    def pop(A,index=-1):B=index;C,D=A._fen_findkth(A._len+B if B<0 else B);E=A._lists[C][D];A._delete(C,D);return E
    def bisect_left(A,value):B,C=A._loc_left(value);return A._fen_query(B)+C
    def bisect_right(A,value):B,C=A._loc_right(value);return A._fen_query(B)+C
    def count(A,value):B=value;return A.bisect_right(B)-A.bisect_left(B)
    def __len__(A):return A._len
    def __getitem__(A,index):B=index;C,D=A._fen_findkth(A._len+B if B<0 else B);return A._lists[C][D]
    def __delitem__(A,index):B=index;C,D=A._fen_findkth(A._len+B if B<0 else B);A._delete(C,D)
    def __contains__(B,value):
        C=value;A=B._lists
        if A:D,E=B._loc_left(C);return E<len(A[D])and A[D][E]==C
        return False
    def __iter__(A):return(B for A in A._lists for B in A)
    def __reversed__(A):return(B for A in reversed(A._lists)for B in reversed(A))
    def __repr__(A):return'SortedList({0})'.format(list(A))
def bit_count(x):x=(x&0x55555555)+((x>>1)&0x55555555);x=(x&0x33333333)+((x>>2)&0x33333333);x=(x&0x0f0f0f0f)+((x>>4)&0x0f0f0f0f);x=(x&0x00ff00ff)+((x>>8)&0x00ff00ff);x=(x&0x0000ffff)+((x>>16)&0x0000ffff);return x
def query(x,y):
    print("?",x,y,flush=True)
    return int(input())

# DP,BS,Greedy,Graph,Contribution,IE,Game,Reverse simulation,Trie,Bits,SortedList,Caching.
def main():
    """
    DP - 10m
    if column i is either black or white, we need to check from [i-y,...i-x] to be all white/black and states before
    that to be the alternating color.
    min number of paint if we color column i as white = (number of tiles to flip from [i-y,...i-x] to i) + min number of paint if we color column prev column as black
    vice versa as black.
    i.e dp[i][color] = min(number of tiles to flip from [i-y,..i-x] to i + dp[i-y-1,..i-x-1][color^1])
    to calculate min number of tiles we can use prefix sum.
    start 14m.
    """
    n,m,x,y=I();grid=[];colors=[[0]*(m+1) for _ in range(2)];dp=[[0,0] for _ in range(m)]
    for i in range(n):
        row=list(str(input()).strip());grid.append(row)
        for j in range(m):
            if row[j]==".":colors[0][j+1]+=1
            else:colors[1][j+1]+=1
    for i in range(m):colors[0][i+1]+=colors[0][i];colors[1][i+1]+=colors[1][i]#white,black
    # print(colors)
    for i in range(m):
        for color in range(2):
            cur=inf
            for j in range(max(0,i-y+1),i-x+2):
                cur=min(cur,colors[color][i+1]-colors[color][j]+dp[j-1][color^1])
                # print(i,j,cur)
            dp[i][color]=cur
    # print(dp)
    print(min(dp[-1]))

###### Comment this out for Python 3 + imports at the top #####
if __name__ == "__main__":
    main()

###### Uncomment this for Python 3 (for deep recursion) ######
# from sys import stdin, setrecursionlimit
# import threading
# from collections import defaultdict as dd
# from collections import deque
# setrecursionlimit(5*10**5);input=stdin.buffer.readline;I=lambda:map(int,input().split())
# threading.stack_size(10**8)
# t = threading.Thread(target=main)
# t.start()
# t.join()