#include <bits/stdc++.h>

using namespace std;

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
#define ordered_set tree<int, null_type,less<int>, rb_tree_tag,tree_order_statistics_node_update>

using ll = long long;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using pil = pair<int, ll>;
using pli = pair<ll, int>;
using piii = pair<int, pii>;
using plll = pair<ll, pll>;
using pib = pair<int, bool>;
using pdi = pair<double, int>;
using pid = pair<int, double>;
using ld = long double;
using piiii = pair<pii, pii>;

#define endl "\n"
#define inf 0x3f3f3f3f3f
#define f first
#define s second

ll gcd(ll a, ll b){return b == 0 ? a : gcd(b, a % b);}
ll lcm(ll a, ll b){return a*b/gcd(a,b);}
ll fpow(ll  b, ll exp, ll mod){if(exp == 0) return 1;ll t = fpow(b,exp/2,mod);if(exp&1) return t*t%mod*b%mod;return t*t%mod;}
ll divmod(ll i, ll j, ll mod){i%=mod,j%=mod;return i*fpow(j,mod-2,mod)%mod;}

int n, k, l;
ll psa[1000001], cnt[1000001];
ld dp[1000001];
string s;

bool f(ld v1, int c1, ld v2, int c2){
    if (abs(v1-v2)<=1e-10) return c1<c2;
    return v1>v2;
}

bool check(ld c){
    memset(cnt, 0, sizeof cnt);
    for (int i=1; i<=n; i++){
        dp[i] = dp[i-1];
        cnt[i] = cnt[i-1];
        if (i<l){
            if (f(psa[i]-c, 1, dp[i], cnt[i])){
                dp[i] = psa[i]-c;
                cnt[i] = 1;
            }
        }else{
            if (f(psa[i]-psa[i-l]-c+dp[i-l], cnt[i-l]+1, dp[i], cnt[i])){
                dp[i] = psa[i]-psa[i-l]-c+dp[i-l];
                cnt[i] = cnt[i-l]+1;
            }
        }
    }
    return cnt[n]<=k;
}

int main() {
    //freopen("cowmbat.in", "r", stdin);
    //freopen("cowmbat.out", "w", stdout);
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> k >> l >> s;
    for (int i=1; i<=n; i++){
        if (s[i-1]<='z'&&s[i-1]>='a') psa[i] = 1;
        psa[i] += psa[i-1];
    }
    ll ans = 1e18;
    ld lo = 0;
    ld hi = 1e18;
    while (hi-lo>1e-10){
        ld mid = (lo+hi)/2;
        if (check(mid)) {
            hi = mid;
        }
        else lo = mid;
    }
    ans = min(ans, (ll) (psa[n]-round(dp[n]+hi*k)));
    for (int i=1; i<=n; i++){
        if (s[i-1]<='Z'&&s[i-1]>='A') psa[i] = 1;
        else psa[i] = 0;
        psa[i] += psa[i-1];
    }
    lo = 0;
    hi = 1e18;
    while (hi-lo>1e-10){
        ld mid = (lo+hi)/2;
        if (check(mid)){
            hi = mid;
        }
        else lo = mid;
    }
    ans = min(ans, (ll) (psa[n]-round(dp[n]+hi*k)));
    cout << ans << endl;
    return 0;
}


#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef pair<ll,ll> pll;
const int N = 1000005;
int a[N];
pll dp[N];
ll n,k,l;

int calc(int lam){
	for(int i=0;i<=n;i++){
		dp[i] = make_pair(INT_MAX, INT_MAX);
	}
	dp[0] = {0, 0};
	for(int i=0;i<n;i++){
		dp[i+1] = min(dp[i+1], {dp[i].first + a[i], dp[i].second});
		dp[min(n,i+l)] = min(dp[min(n,i+l)], {dp[i].first + lam, dp[i].second + 1});
	}

	return dp[n].second;
}

int solve(){
	int l=0;
	//max val of the dp can be n and hence the max lambda to choose is n
	int r=n;
	int lambda = 0;
	// find min lamda such that number of selected elems <= k
	// as lambda increases calc(lambda) decreases
	while(l<=r){
		int m = (l+r)>>1;
		if(calc(m) > k){
			lambda = m;
			l = m+1;
		}else{
			r = m-1;
		}
	}
	// for each value of lambda we require less than k ops. => we require no ops
	if(calc(lambda) <= k) return 0;

	calc(lambda+1);
	return dp[n].first - (lambda+1LL) * 1LL * k;
}

int main(){
	cin >> n >> k >> l;
	string s; cin >> s;

	/*try to solve two cases
		case 1: miminum number of lowercase chars if K toLower allowed
		case 2: miminum number of uppercase chars if K toUpper allowed
	*/

	for(int i=0;i<n;i++){
		a[i] = islower(s[i])? 0:1;
	}

	/*dp[n][k]: prefix sum of a[0] to a[n] such that k ops have been applied
		let ans[k] be ans if atmost k ops were applied.
		ans[k] is a decreasing sequence
		then ans[k-1] - ans[k] >= ans[k] - ans[k+1]
		so the function is convex and we need to shift peak to left
		hence we use ans[i] + lambda*i and find lambda
	*/
	int ans = INT_MAX;
	ans = min(ans, solve());

	for(int i=0;i<n;i++){
		a[i] = isupper(s[i])? 0:1;
	}
	ans = min(ans, solve());
	cout << ans << endl;

	return 0;
}


#pragma GCC optimize ("O3")
#pragma GCC optimize ("unroll-loops")
#pragma comment(linker, "/STACK:2000000")

#include "bits/stdc++.h"

using namespace std;

#define pb push_back
#define F first
#define S second
#define f(i,a,b)  for(int i = a; i < b; i++)
// #define endl '\n'
using ll = long long;
using db = long double;
using ii = pair<int, int>;

const int N = 1e6+5, LG = 19, MOD = 998244353;
const int SQ =320;
const long double EPS = 1e-7;
int n, k, l;
pair<ll, int> dp[N];
pair<ll,int> check(vector<int> & v, ll penalty){
  deque<int> dq;
  for(int i = 0; i <= n; i++){
    while(dq.size()&&i-dq.front()> l)dq.pop_front();
    if(i)
      dp[i] = dp[i-1];
    dp[i].F+=v[i];
    if(i >= l){
      dp[i] = min(dp[i], make_pair(penalty+dp[dq.front()].first,dp[dq.front()].second+1));
    }
    while(dq.size()&& dp[i] < dp[dq.back()])dq.pop_back();
    dq.push_back(i);
  }
  return dp[n];
}
int solve(vector<int> v){
  ll lo = -1e6, hi = 1e6;
  while(lo < hi){

    ll md = lo + (hi-lo)/2;
    ///as the penalty increases the number of operations decreases
    if(check(v,md).S<=k)
      hi = md;
    else
      lo = md + 1;

  }
  ///my function is a minimizing function
  auto x = check(v,lo);
  return x.F - k * lo;
}
int32_t main(){
#ifdef ONLINE_JUDGE
    ios_base::sync_with_stdio(0);
    cin.tie(0);
#endif

  cin >> n >> k >> l;

  vector<int> v1({0}), v2({0});
  string s;
  cin >> s;

  f(i,0,n){
    v1.pb((bool)islower(s[i]));
    v2.pb((bool)isupper(s[i]));
  }

  cout << min(solve(v1),solve(v2)) << '\n';

  return 0;
}


#pragma GCC optimize ("O3")
#pragma GCC optimize ("unroll-loops")
#pragma comment(linker, "/STACK:2000000")

#include "bits/stdc++.h"

using namespace std;

#define pb push_back
#define F first
#define S second
#define f(i,a,b)  for(int i = a; i < b; i++)
// #define endl '\n'
using ll = long long;
using db = long double;
using ii = pair<int, int>;

const int N = 1e6+5, LG = 19, MOD = 998244353;
const int SQ =320;
const long double EPS = 1e-7;
int n, k, l;
pair<ll, int> dp[N];
pair<ll,int> check(vector<int> & v, ll penalty){
  deque<int> dq;
  for(int i = 0; i <= n; i++){
    while(dq.size()&&i-dq.front()> l)dq.pop_front();
    if(i)
      dp[i] = dp[i-1];
    dp[i].F+=v[i];
    if(i >= l){
      dp[i] = min(dp[i], make_pair(penalty+dp[dq.front()].first,dp[dq.front()].second+1));
    }
    while(dq.size()&& dp[i] < dp[dq.back()])dq.pop_back();
    dq.push_back(i);
  }
  return dp[n];
}
int solve(vector<int> v){
  ll lo = 0, hi = 1e6;
  while(lo < hi){

    ll md = lo + (hi-lo)/2;
    ///as the penalty increases the number of operations decreases
    if(check(v,md).S<=k)
      hi = md;
    else
      lo = md + 1;

  }
  ///my function is a minimizing function
  auto x = check(v,lo);
  return x.F - k * lo;
}
int32_t main(){
#ifdef ONLINE_JUDGE
    ios_base::sync_with_stdio(0);
    cin.tie(0);
#endif

  cin >> n >> k >> l;

  vector<int> v1({0}), v2({0});
  string s;
  cin >> s;

  f(i,0,n){
    v1.pb((bool)islower(s[i]));
    v2.pb((bool)isupper(s[i]));
  }

  cout << min(solve(v1),solve(v2)) << '\n';

  return 0;
}


#include <bits/stdc++.h>

using namespace std;

const int N=1e6;
int dp[2*N],cnt[2*N],n,k,l,price,ans=N;
string s;
void calc(){
    for(int i=n-1;i>=0;i--){
        dp[i]=dp[i+1]+(s[i]>='a');
        cnt[i]=cnt[i+1];
        if(dp[i+l]+price<dp[i])
            dp[i]=dp[i+l]+price,cnt[i]=cnt[i+l]+1;
    }
}
void solve(){
    int le=0,ri=N;
	while(le<ri){
        price=(le+ri)>>1;
        calc();
        if(cnt[0]>k)
            le=price+1;
        else
            ri=price;
	}
	price=le;
	calc();
	int sol=dp[0]-price*k;
	ans=min(ans,sol);
}
int main()
{
	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cin >> n >> k >> l >> s;
	solve();
	for(int i=0;i<n;i++)
        if(s[i]>='a')
            s[i]-='a'-'A';
        else
            s[i]-='A'-'a';
    solve();
    printf("%i\n",ans);
    return 0;
}


#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

#define ll long long
#define pb push_back
#define mp make_pair
#define f first
#define s second
#define sz(x) (int)x.size()
#define all(x) x.begin(), x.end()

using namespace std;
using namespace __gnu_pbds;

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
template<class T> using ordered_set = tree<T, null_type, less<T>, rb_tree_tag,tree_order_statistics_node_update>; ///find_by_order(),order_of_key()
template<class T1, class T2> ostream& operator<<(ostream& os, const pair<T1,T2>& a) { os << '{' << a.f << ", " << a.s << '}'; return os; }
template<class T> ostream& operator<<(ostream& os, const vector<T>& a){os << '{';for(int i=0;i<sz(a);i++){if(i>0&&i<sz(a))os << ", ";os << a[i];}os<<'}';return os;}
template<class T> ostream& operator<<(ostream& os, const set<T>& a) {os << '{';int i=0;for(auto p:a){if(i>0&&i<sz(a))os << ", ";os << p;i++;}os << '}';return os;}
template<class T> ostream& operator<<(ostream& os, const multiset<T>& a) {os << '{';int i=0;for(auto p:a){if(i>0&&i<sz(a))os << ", ";os << p;i++;}os << '}';return os;}
template<class T1,class T2> ostream& operator<<(ostream& os, const map<T1,T2>& a) {os << '{';int i=0;for(auto p:a){if(i>0&&i<sz(a))os << ", ";os << p;i++;}os << '}';return os;}
template<class T1,class T2> ostream& operator<<(ostream& os, const gp_hash_table<T1,T2>& a) {os << '{';int i=0;for(auto p:a){if(i>0&&i<sz(a))os << ", ";os << p;i++;}os << '}';return os;}

const int N=1e6+5;
ll dp[N],cnt[2*N],n,k,l,price,ans=N;
string s;
ll calc(int tr){
    if(tr>=n)
        return cnt[tr]=0;
    if(dp[tr]!=-1)
        return dp[tr];
    dp[tr]=calc(tr+1)+(s[tr]>='a');
    cnt[tr]=cnt[tr+1];
    if(calc(tr+l)+price<dp[tr])
        dp[tr]=calc(tr+l)+price,cnt[tr]=cnt[tr+l]+1;
    return dp[tr];
}
void solve(){
    //cout << s << endl;
    int le=0,ri=N;
	while(le<ri){
        price=(le+ri)>>1;
        memset(dp,-1,sizeof(dp));
        calc(0);
        if(cnt[0]>k)
            le=price+1;
        else
            ri=price;
	}
	price=le;
	memset(dp,-1,sizeof(dp));
	ll sol=calc(0)-price*cnt[0];
	if(cnt[0]!=k){
        int down=dp[0]-cnt[0]*price,c=cnt[0];
        price--;
        memset(dp,-1,sizeof(dp));
        calc(0);
        int up=dp[0]-cnt[0]*price,cup=cnt[0];
        assert((up-down)%(cup-c)==0);
        //printf("%i %i  %i %i\n",down,up,c,cup);
        sol=down+(up-down)*(k-c)/(cnt[0]-c);
	}
	ans=min(ans,sol);
}
int main()
{
	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cin >> n >> k >> l >> s;
	solve();
	for(int i=0;i<n;i++)
        if(s[i]>='a')
            s[i]-='a'-'A';
        else
            s[i]-='A'-'a';
    solve();
    printf("%i\n",ans);
    return 0;
}


#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

#define ll long long
#define pb push_back
#define mp make_pair
#define f first
#define s second
#define sz(x) (int)x.size()
#define all(x) x.begin(), x.end()

using namespace std;
using namespace __gnu_pbds;

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
template<class T> using ordered_set = tree<T, null_type, less<T>, rb_tree_tag,tree_order_statistics_node_update>; ///find_by_order(),order_of_key()
template<class T1, class T2> ostream& operator<<(ostream& os, const pair<T1,T2>& a) { os << '{' << a.f << ", " << a.s << '}'; return os; }
template<class T> ostream& operator<<(ostream& os, const vector<T>& a){os << '{';for(int i=0;i<sz(a);i++){if(i>0&&i<sz(a))os << ", ";os << a[i];}os<<'}';return os;}
template<class T> ostream& operator<<(ostream& os, const set<T>& a) {os << '{';int i=0;for(auto p:a){if(i>0&&i<sz(a))os << ", ";os << p;i++;}os << '}';return os;}
template<class T> ostream& operator<<(ostream& os, const multiset<T>& a) {os << '{';int i=0;for(auto p:a){if(i>0&&i<sz(a))os << ", ";os << p;i++;}os << '}';return os;}
template<class T1,class T2> ostream& operator<<(ostream& os, const map<T1,T2>& a) {os << '{';int i=0;for(auto p:a){if(i>0&&i<sz(a))os << ", ";os << p;i++;}os << '}';return os;}
template<class T1,class T2> ostream& operator<<(ostream& os, const gp_hash_table<T1,T2>& a) {os << '{';int i=0;for(auto p:a){if(i>0&&i<sz(a))os << ", ";os << p;i++;}os << '}';return os;}

const int N=1e6+5;
int dp[N],cnt[2*N],n,k,l,price,ans=N;
string s;
int calc(int tr){
    if(tr>=n)
        return cnt[tr]=0;
    if(dp[tr]!=-1)
        return dp[tr];
    dp[tr]=calc(tr+1)+(s[tr]>='a');
    cnt[tr]=cnt[tr+1];
    if(calc(tr+l)+price<dp[tr])
        dp[tr]=calc(tr+l)+price,cnt[tr]=cnt[tr+l]+1;
    return dp[tr];
}
void solve(){
    int le=0,ri=N;
	while(le<ri){
        price=(le+ri)>>1;
        memset(dp,-1,sizeof(dp));
        calc(0);
        if(cnt[0]>k)
            le=price+1;
        else
            ri=price;
	}
	price=le;
	memset(dp,-1,sizeof(dp));
	int sol=calc(0)-price*cnt[0];
	if(cnt[0]!=k){
        int down=dp[0]-cnt[0]*price,c=cnt[0];
        price--;
        memset(dp,-1,sizeof(dp));
        calc(0);
        sol=down+(dp[0]-cnt[0]*price-down)/(cnt[0]-c)*(k-c);
	}
	ans=min(ans,sol);
}
int main()
{
	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cin >> n >> k >> l >> s;
	solve();
	for(int i=0;i<n;i++)
        if(s[i]>='a')
            s[i]-='a'-'A';
        else
            s[i]-='A'-'a';
    solve();
    printf("%i\n",ans);
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

const int N=1e6;
int dp[2*N],cnt[2*N],n,k,l,price,ans=N;
string s;
void solve(){
    int le=0,ri=N,sol;
	while(le<ri){
        price=(le+ri)>>1;
        for(int i=n-1;i>=0;i--){
            dp[i]=dp[i+1]+(s[i]>='a');
            cnt[i]=cnt[i+1];
            if(dp[i+l]+price<dp[i])
                dp[i]=dp[i+l]+price,cnt[i]=cnt[i+l]+1;
        }
        if(cnt[0]>k)
            le=price+1;
        else
            ri=price,sol=dp[0]-price*k;
	}
	ans=min(ans,sol);
}
int main()
{
	cin >> n >> k >> l >> s;
	solve();
	for(int i=0;i<n;i++)
        if(s[i]>='a')
            s[i]-='a'-'A';
        else
            s[i]-='A'-'a';
    solve();
    printf("%i\n",ans);
    return 0;
}


#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

#define ll long long
#define pb push_back
#define mp make_pair
#define f first
#define s second
#define sz(x) (int)x.size()
#define all(x) x.begin(), x.end()

using namespace std;
using namespace __gnu_pbds;

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
template<class T> using ordered_set = tree<T, null_type, less<T>, rb_tree_tag,tree_order_statistics_node_update>; ///find_by_order(),order_of_key()
template<class T1, class T2> ostream& operator<<(ostream& os, const pair<T1,T2>& a) { os << '{' << a.f << ", " << a.s << '}'; return os; }
template<class T> ostream& operator<<(ostream& os, const vector<T>& a){os << '{';for(int i=0;i<sz(a);i++){if(i>0&&i<sz(a))os << ", ";os << a[i];}os<<'}';return os;}
template<class T> ostream& operator<<(ostream& os, const set<T>& a) {os << '{';int i=0;for(auto p:a){if(i>0&&i<sz(a))os << ", ";os << p;i++;}os << '}';return os;}
template<class T> ostream& operator<<(ostream& os, const multiset<T>& a) {os << '{';int i=0;for(auto p:a){if(i>0&&i<sz(a))os << ", ";os << p;i++;}os << '}';return os;}
template<class T1,class T2> ostream& operator<<(ostream& os, const map<T1,T2>& a) {os << '{';int i=0;for(auto p:a){if(i>0&&i<sz(a))os << ", ";os << p;i++;}os << '}';return os;}
template<class T1,class T2> ostream& operator<<(ostream& os, const gp_hash_table<T1,T2>& a) {os << '{';int i=0;for(auto p:a){if(i>0&&i<sz(a))os << ", ";os << p;i++;}os << '}';return os;}

const int N=1e6+5;
int dp[2*N],cnt[2*N],n,k,l,price,ans=N;
string s;
void calc(){
    for(int i=n-1;i>=0;i--){
        dp[i]=dp[i+1]+(s[i]>='a');
        cnt[i]=cnt[i+1];
        if(dp[i+l]+price<dp[i])
            dp[i]=dp[i+l]+price,cnt[i]=cnt[i+l]+1;
    }
}
void solve(){
    int le=0,ri=N;
	while(le<ri){
        price=(le+ri)>>1;
        calc();
        if(cnt[0]>k)
            le=price+1;
        else
            ri=price;
	}
	price=le;
	calc();
	int sol=dp[0]-price*cnt[0];
	if(cnt[0]!=k){
        int down=dp[0]-cnt[0]*price,c=cnt[0];
        price--;
        calc();
        sol=down+(dp[0]-cnt[0]*price-down)/(cnt[0]-c)*(k-c);
	}
	ans=min(ans,sol);
}
int main()
{
	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cin >> n >> k >> l >> s;
	solve();
	for(int i=0;i<n;i++)
        if(s[i]>='a')
            s[i]-='a'-'A';
        else
            s[i]-='A'-'a';
    solve();
    printf("%i\n",ans);
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

const int N=1e6;
int dp[2*N],cnt[2*N],n,k,l,price,ans=N;
string s;
void calc(){
    for(int i=n-1;i>=0;i--){
        dp[i]=dp[i+1]+(s[i]>='a');
        cnt[i]=cnt[i+1];
        if(dp[i+l]+price<dp[i])
            dp[i]=dp[i+l]+price,cnt[i]=cnt[i+l]+1;
    }
}
void solve(){
    int le=0,ri=N/1024;
	while(le<ri){
        price=(le+ri)>>1;
        calc();
        if(cnt[0]>k)
            le=price+1;
        else
            ri=price;
	}
	price=le;
	calc();
	int sol=dp[0]-price*cnt[0];
	if(cnt[0]!=k){
        int down=dp[0]-cnt[0]*price,c=cnt[0];
        price--;
        calc();
        sol=down+(dp[0]-cnt[0]*price-down)/(cnt[0]-c)*(k-c);
	}
	ans=min(ans,sol);
}
int main()
{
	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cin >> n >> k >> l >> s;
	solve();
	for(int i=0;i<n;i++)
        if(s[i]>='a')
            s[i]-='a'-'A';
        else
            s[i]-='A'-'a';
    solve();
    printf("%i\n",ans);
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

const int N=1e6;
int dp[2*N],cnt[2*N],n,k,l,price,ans=N;
string s;
void calc(){
    for(int i=n-1;i>=0;i--){
        dp[i]=dp[i+1]+(s[i]>='a');
        cnt[i]=cnt[i+1];
        if(dp[i+l]+price<dp[i])
            dp[i]=dp[i+l]+price,cnt[i]=cnt[i+l]+1;
    }
}
void solve(){
    int le=0,ri=N/16;
	while(le<ri){
        price=(le+ri)>>1;
        calc();
        if(cnt[0]>k)
            le=price+1;
        else
            ri=price;
	}
	price=le;
	calc();
	int sol=dp[0]-price*cnt[0];
	if(cnt[0]!=k){
        int down=dp[0]-cnt[0]*price,c=cnt[0];
        price--;
        calc();
        sol=down+(dp[0]-cnt[0]*price-down)/(cnt[0]-c)*(k-c);
	}
	ans=min(ans,sol);
}
int main()
{
	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cin >> n >> k >> l >> s;
	solve();
	for(int i=0;i<n;i++)
        if(s[i]>='a')
            s[i]-='a'-'A';
        else
            s[i]-='A'-'a';
    solve();
    printf("%i\n",ans);
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
const int N=1e6;
int dp[2*N],cnt[2*N],n,k,l,p,ans=N;
char s[N];
void solve(){
    int le=0,ri=N,sol;
	while(le<ri){
        p=(le+ri)>>1;
        for(int i=n-1;i>=0;i--){
            dp[i]=dp[i+1]+(s[i]>96);
            cnt[i]=cnt[i+1];
            if(dp[i+l]+p<dp[i])
                dp[i]=dp[i+l]+p,cnt[i]=cnt[i+l]+1;
        }
        if(cnt[0]>k)
            le=p+1;
        else
            ri=p,sol=dp[0]-p*k;
	}
	if(ans)
	ans=min(ans,sol);
}
void f(int &number)
{
    char c;
    number = 0;
    c = getchar();
    for (; (c>47 && c<58); c=getchar())
        number = number *10 + c - 48;
}
int main()
{
    f(n);
    f(k);
    f(l);
    for(int i=0;i<n;i++)
        s[i]=getchar();
	solve();
	for(auto &p:s)
        p=(p+32)%125;
    solve();
    printf("%i\n",ans);
    return 0;
}


#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

#define ll long long
#define pb push_back
#define mp make_pair
#define f first
#define s second
#define sz(x) (int)x.size()
#define all(x) x.begin(), x.end()

using namespace std;
using namespace __gnu_pbds;

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
template<class T> using ordered_set = tree<T, null_type, less<T>, rb_tree_tag,tree_order_statistics_node_update>; ///find_by_order(),order_of_key()
template<class T1, class T2> ostream& operator<<(ostream& os, const pair<T1,T2>& a) { os << '{' << a.f << ", " << a.s << '}'; return os; }
template<class T> ostream& operator<<(ostream& os, const vector<T>& a){os << '{';for(int i=0;i<sz(a);i++){if(i>0&&i<sz(a))os << ", ";os << a[i];}os<<'}';return os;}
template<class T> ostream& operator<<(ostream& os, const set<T>& a) {os << '{';int i=0;for(auto p:a){if(i>0&&i<sz(a))os << ", ";os << p;i++;}os << '}';return os;}
template<class T> ostream& operator<<(ostream& os, const multiset<T>& a) {os << '{';int i=0;for(auto p:a){if(i>0&&i<sz(a))os << ", ";os << p;i++;}os << '}';return os;}
template<class T1,class T2> ostream& operator<<(ostream& os, const map<T1,T2>& a) {os << '{';int i=0;for(auto p:a){if(i>0&&i<sz(a))os << ", ";os << p;i++;}os << '}';return os;}
template<class T1,class T2> ostream& operator<<(ostream& os, const gp_hash_table<T1,T2>& a) {os << '{';int i=0;for(auto p:a){if(i>0&&i<sz(a))os << ", ";os << p;i++;}os << '}';return os;}

const int N=1e6+5;
int dp[N],cnt[N],n,k,l,price,ans=N;
string s;
void calc(){
    dp[n]=cnt[n]=0;
    for(int i=n-1;i>=0;i--){
        dp[i]=dp[i+1]+(s[i]>='a');
        cnt[i]=cnt[i+1];
        if(i+l<=n&&dp[i+l]+price<dp[i])
            dp[i]=dp[i+l]+price,cnt[i]=cnt[i+l]+1;
    }
}
void solve(){
    int le=0,ri=N;
	while(le<ri){
        price=(le+ri)>>1;
        calc();
        if(cnt[0]>k)
            le=price+1;
        else
            ri=price;
	}
	price=le;
	calc();
	int sol=dp[0]-price*cnt[0];
	if(cnt[0]!=k){
        int down=dp[0]-cnt[0]*price,c=cnt[0];
        price--;
        calc();
        sol=down+(dp[0]-cnt[0]*price-down)/(cnt[0]-c)*(k-c);
	}
	ans=min(ans,sol);
}
int main()
{
	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cin >> n >> k >> l >> s;
	solve();
	for(int i=0;i<n;i++)
        if(s[i]>='a')
            s[i]-='a'-'A';
        else
            s[i]-='A'-'a';
    solve();
    printf("%i\n",ans);
    return 0;
}


#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

#define ll long long
#define pb push_back
#define mp make_pair
#define f first
#define s second
#define sz(x) (int)x.size()
#define all(x) x.begin(), x.end()

using namespace std;
using namespace __gnu_pbds;

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
template<class T> using ordered_set = tree<T, null_type, less<T>, rb_tree_tag,tree_order_statistics_node_update>; ///find_by_order(),order_of_key()
template<class T1, class T2> ostream& operator<<(ostream& os, const pair<T1,T2>& a) { os << '{' << a.f << ", " << a.s << '}'; return os; }
template<class T> ostream& operator<<(ostream& os, const vector<T>& a){os << '{';for(int i=0;i<sz(a);i++){if(i>0&&i<sz(a))os << ", ";os << a[i];}os<<'}';return os;}
template<class T> ostream& operator<<(ostream& os, const set<T>& a) {os << '{';int i=0;for(auto p:a){if(i>0&&i<sz(a))os << ", ";os << p;i++;}os << '}';return os;}
template<class T> ostream& operator<<(ostream& os, const multiset<T>& a) {os << '{';int i=0;for(auto p:a){if(i>0&&i<sz(a))os << ", ";os << p;i++;}os << '}';return os;}
template<class T1,class T2> ostream& operator<<(ostream& os, const map<T1,T2>& a) {os << '{';int i=0;for(auto p:a){if(i>0&&i<sz(a))os << ", ";os << p;i++;}os << '}';return os;}
template<class T1,class T2> ostream& operator<<(ostream& os, const gp_hash_table<T1,T2>& a) {os << '{';int i=0;for(auto p:a){if(i>0&&i<sz(a))os << ", ";os << p;i++;}os << '}';return os;}

const int N=1e6+5;
int dp[2*N],cnt[2*N],n,k,l,price,ans=N;
string s;
void calc(){
    for(int i=n-1;i>=0;i--){
        dp[i]=dp[i+1]+(s[i]>='a');
        cnt[i]=cnt[i+1];
        if(dp[i+l]+price<dp[i])
            dp[i]=dp[i+l]+price,cnt[i]=cnt[i+l]+1;
    }
}
void solve(){
    int le=0,ri=N;
	while(le<ri){
        price=(le+ri)>>1;
        calc();
        if(cnt[0]>k)
            le=price+1;
        else
            ri=price;
	}
	price=le;
	calc();
	int sol=dp[0]-price*k;
	ans=min(ans,sol);
}
int main()
{
	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cin >> n >> k >> l >> s;
	solve();
	for(int i=0;i<n;i++)
        if(s[i]>='a')
            s[i]-='a'-'A';
        else
            s[i]-='A'-'a';
    solve();
    printf("%i\n",ans);
    return 0;
}


#include<iostream>
using namespace std;const int N=1<<21;long long d[N],n,k,l,p,i;string s;f(int m){int q=0,p=N,b;while(q<p){p=(q+p)/2;for(i=n-1;~i;i--){d[i]=d[i+1]+(s[i]^m);if((d[i+l]+p)%N<d[i]%N)d[i]=d[i+l]+p+N;}if(d[0]/N>k)q=p+1;else p=p,b=d[0]%N-p*k;}return b;}main(){cin>>n>>k>>l>>s;for(auto&p:s)p=p>96;cout<<min(f(0),f(1));}


#include <bits/stdc++.h>
#define v q=0;w=N;while(q<w){p=(q+w)>>1;for(int i=n-1;i>=0;i--){d[i]=d[i+1]+(s[i]>96);c[i]=c[i+1];if(d[i+l]+p<d[i])d[i]=d[i+l]+p,c[i]=c[i+l]+1;}if(c[0]>k)q=p+1;else w=p,u=d[0]-p*k;}a=min(a,u)
using namespace std;const int N=1e6;int d[2*N],c[2*N],n,k,l,p,a=N,q,w,u;string s;int main(){cin>>n>>k>>l>>s;v;for(auto &p:s)p=(p+32)%125;v;printf("%i\n",a);}


#include <bits/stdc++.h>

using namespace std;

const int N=1e6+5;
int dp[2*N],cnt[2*N],n,k,l,price,ans=N;
string s;
void calc(){
    for(int i=n-1;i>=0;i--){
        dp[i]=dp[i+1]+(s[i]>='a');
        cnt[i]=cnt[i+1];
        if(dp[i+l]+price<dp[i])
            dp[i]=dp[i+l]+price,cnt[i]=cnt[i+l]+1;
    }
}
void solve(){
    int le=0,ri=N/2;
	while(le<ri){
        price=(le+ri)>>1;
        calc();
        if(cnt[0]>k)
            le=price+1;
        else
            ri=price;
	}
	price=le;
	calc();
	int sol=dp[0]-price*cnt[0];
	if(cnt[0]!=k){
        int down=dp[0]-cnt[0]*price,c=cnt[0];
        price--;
        calc();
        sol=down+(dp[0]-cnt[0]*price-down)/(cnt[0]-c)*(k-c);
	}
	ans=min(ans,sol);
}
int main()
{
	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cin >> n >> k >> l >> s;
	solve();
	for(int i=0;i<n;i++)
        if(s[i]>='a')
            s[i]-='a'-'A';
        else
            s[i]-='A'-'a';
    solve();
    printf("%i\n",ans);
    return 0;
}


#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

#define ll long long
#define pb push_back
#define mp make_pair
#define f first
#define s second
#define sz(x) (int)x.size()
#define all(x) x.begin(), x.end()

using namespace std;
using namespace __gnu_pbds;

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
template<class T> using ordered_set = tree<T, null_type, less<T>, rb_tree_tag,tree_order_statistics_node_update>; ///find_by_order(),order_of_key()
template<class T1, class T2> ostream& operator<<(ostream& os, const pair<T1,T2>& a) { os << '{' << a.f << ", " << a.s << '}'; return os; }
template<class T> ostream& operator<<(ostream& os, const vector<T>& a){os << '{';for(int i=0;i<sz(a);i++){if(i>0&&i<sz(a))os << ", ";os << a[i];}os<<'}';return os;}
template<class T> ostream& operator<<(ostream& os, const set<T>& a) {os << '{';int i=0;for(auto p:a){if(i>0&&i<sz(a))os << ", ";os << p;i++;}os << '}';return os;}
template<class T> ostream& operator<<(ostream& os, const multiset<T>& a) {os << '{';int i=0;for(auto p:a){if(i>0&&i<sz(a))os << ", ";os << p;i++;}os << '}';return os;}
template<class T1,class T2> ostream& operator<<(ostream& os, const map<T1,T2>& a) {os << '{';int i=0;for(auto p:a){if(i>0&&i<sz(a))os << ", ";os << p;i++;}os << '}';return os;}
template<class T1,class T2> ostream& operator<<(ostream& os, const gp_hash_table<T1,T2>& a) {os << '{';int i=0;for(auto p:a){if(i>0&&i<sz(a))os << ", ";os << p;i++;}os << '}';return os;}

const int N=1e6+5;
int dp[N],cnt[2*N],n,k,l,price,ans=N;
string s;
int calc(int tr){
    if(tr>=n)
        return cnt[tr]=0;
    if(dp[tr]!=-1)
        return dp[tr];
    dp[tr]=calc(tr+1)+(s[tr]>='a');
    cnt[tr]=cnt[tr+1];
    if(calc(tr+l)+price<dp[tr])
        dp[tr]=calc(tr+l)+price,cnt[tr]=cnt[tr+l]+1;
    return dp[tr];
}
void solve(){
    //cout << s << endl;
    int le=0,ri=N;
	while(le<ri){
        price=(le+ri)>>1;
        memset(dp,-1,sizeof(dp));
        calc(0);
        if(cnt[0]>k)
            le=price+1;
        else
            ri=price;
	}
	price=le;
	memset(dp,-1,sizeof(dp));
	int sol=calc(0)-price*k;
	if(cnt[0]!=k){
        int down=dp[0]-cnt[0]*price,c=cnt[0];
        price--;
        memset(dp,-1,sizeof(dp));
        calc(0);
        int up=dp[0]-cnt[0]*price,cup=cnt[0];
        assert((up-down)%(cup-c)==0);
        //printf("%i %i  %i %i\n",down,up,c,cup);
        sol=down+(up-down)*(k-c)/(cnt[0]-c);
	}
	ans=min(ans,sol);
}
int main()
{
	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cin >> n >> k >> l >> s;
	solve();
	for(int i=0;i<n;i++)
        if(s[i]>='a')
            s[i]-='a'-'A';
        else
            s[i]-='A'-'a';
    solve();
    printf("%i\n",ans);
    return 0;
}


#include <bits/stdc++.h>
#define v q=0;w=N;while(q<w){p=(q+w)>>1;for(int i=n-1;i>=0;i--){d[i]=d[i+1]+(s[i]>96);c[i]=c[i+1];if(d[i+l]+p<d[i])d[i]=d[i+l]+p,c[i]=c[i+l]+1;}if(c[0]>k)q=p+1;else w=p,u=d[0]-p*k;}a=min(a,u)
using namespace std;const int N=1e6;int d[2*N],c[2*N],n,k,l,p,a=N,q,w,u;string s;int main(){cin>>n>>k>>l>>s;v;for(auto &p:s)p=(p+32)%120;v;printf("%i\n",a);}


#include<iostream>
using namespace std;
const int N=1<<21;
long long d[N],n,k,l,o,i;
string s;
f(int m){
    int q=0,p=N,b;
	while(q<p){
        o=(q+p)/2;
        for(i=n-1;~i;i--){
            d[i]=d[i+1]+(s[i]^m);
            if((d[i+l]+o)%N<d[i]%N)
                d[i]=d[i+l]+o+N;
        }
        if(d[0]/N>k)
            q=o+1;
        else
            p=o,b=d[0]%N-o*k;
	}
	return b;
}
main()
{
	cin>>n>>k>>l>>s;
	for(auto&p:s)
        p=p>96;
    cout<<min(f(0),f(1));
}


#include "bits/stdc++.h"
using namespace std;

#define FAST ios_base::sync_with_stdio(false); cin.tie(0);
#define pb push_back
#define eb emplace_back
#define ins insert
#define ph push
#define f first
#define s second
#define cbr cerr << "hi\n"
#define mmst(x, v) memset((x), v, sizeof ((x)))
#define siz(x) ll(x.size())
#define all(x) (x).begin(), (x).end()
#define lbd(x, y) lower_bound(all(x), y)
#define ubd(x, y) upper_bound(all(x), y)
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());    //can be used by calling rng() or shuffle(A, A+n, rng)
inline long long rand(long long x, long long y) { return (rng() % (y+1-x)) + x; } //inclusivesss
string inline to_string(char c) {string s(1,c);return s;} template<typename T> inline T gcd(T a,T b){ return a==0?llabs(b):gcd(b%a,a); }

typedef long long ll;
typedef long double ld;
#define FOR(i,s,e) for(ll i=s;i<=ll(e);++i)
#define DEC(i,s,e) for(ll i=s;i>=ll(e);--i)
typedef pair<ll,ll>pi; typedef pair<ll,pi>spi; typedef pair<pi,pi>dpi;

#define LLINF ((long long) 1e18)//1234567890987654321
#define INF 1234567890ll
// #define cerr if(0)cout
#define MAXN (300006)
int main()
{
	FAST
	ll n,k,l;
	cin>>n>>k>>l;
	string s; cin>>s;
	s='*'+s;
	ll lw=0,up=0;
	FOR(i,1,n)lw+=('a'<=s[i]&&s[i]<='z'), up+=('A'<=s[i]&&s[i]<='Z');
	auto b=[&](pi x,pi y) {
		if(x.f > y.f || (x.f==y.f&&x.s<y.s)) return 1;
		return 0;
	};
	auto g=[&](pi x,pi y){
		if(x.f > y.f || (x.f==y.f&&x.s>y.s)) return 1;
		return 0;
	};
	vector<ll> lc(n+1, 0);
	auto solve1=[&]() { // min lower case
		vector<pi> dp(n+1, pi(0,0));
		auto bstar_ans=[&](ll x) {
			dp[0] = pi(0, 0);
			deque<spi> dq;
			dq.eb(0,dp[0]);
			FOR(i,1,n) {
				while(dq.size() && i-dq.front().f > l) dq.pop_front();
				assert(dq.size());
				if(g(dp[i-1], pi(dq[0].s.f+lc[i]-x,dq[0].s.s+1))) {
					dp[i]=dp[i-1];
				} else {
					dp[i]=pi(dq[0].s.f+lc[i]-x, dq[0].s.s+1);
				}
				while(dq.size() && g(pi(dp[i].f-lc[i],dp[i].s),dq.back().s)) dq.pop_back();
				dq.eb(i, pi(dp[i].f-lc[i],dp[i].s));
			}
			// cerr<<dp[n].f<<' '<<dp[n].s<<'\n';
			return dp[n];
		};
		auto bstar=[&](ll x) {
			dp[0] = pi(0, 0);
			deque<spi> dq;
			dq.eb(0,dp[0]);
			FOR(i,1,n) {
				while(dq.size() && i-dq.front().f > l) dq.pop_front();
				assert(dq.size());
				if(b(dp[i-1], pi(dq[0].s.f+lc[i]-x,dq[0].s.s+1))) {
					dp[i]=dp[i-1];
				} else {
					dp[i]=pi(dq[0].s.f+lc[i]-x, dq[0].s.s+1);
				}
				while(dq.size() && b(pi(dp[i].f-lc[i],dp[i].s),dq.back().s)) dq.pop_back();
				dq.eb(i, pi(dp[i].f-lc[i],dp[i].s));
			}
			// cerr<<dp[n].f<<' '<<dp[n].s<<'\n';
			return dp[n];
		};
		ll st=-1,en=n+1,mid=0;
		while(en-st>1) {
			mid=(st+en)>>1;
			if(bstar(mid).s <= k) en=mid;
			else st=mid;
		}
		return bstar_ans(en).f+en*min(bstar_ans(en).s, k);
	};
	FOR(i,1,n) lc[i]=lc[i-1]+('a'<=s[i]&&s[i]<='z');
	ll ans = lw-solve1();
	FOR(i,1,n) lc[i]=lc[i-1]+('A'<=s[i]&&s[i]<='Z');
	ans = min(ans, up-solve1());
	cout<<ans<<'\n';
}


#include "bits/stdc++.h"
using namespace std;

#define FAST ios_base::sync_with_stdio(false); cin.tie(0);
#define pb push_back
#define eb emplace_back
#define ins insert
#define ph push
#define f first
#define s second
#define cbr cerr << "hi\n"
#define mmst(x, v) memset((x), v, sizeof ((x)))
#define siz(x) ll(x.size())
#define all(x) (x).begin(), (x).end()
#define lbd(x, y) lower_bound(all(x), y)
#define ubd(x, y) upper_bound(all(x), y)
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());    //can be used by calling rng() or shuffle(A, A+n, rng)
inline long long rand(long long x, long long y) { return (rng() % (y+1-x)) + x; } //inclusivesss
string inline to_string(char c) {string s(1,c);return s;} template<typename T> inline T gcd(T a,T b){ return a==0?llabs(b):gcd(b%a,a); }

typedef long long ll;
typedef long double ld;
#define FOR(i,s,e) for(ll i=s;i<=ll(e);++i)
#define DEC(i,s,e) for(ll i=s;i>=ll(e);--i)
typedef pair<ll,ll>pi; typedef pair<ll,pi>spi; typedef pair<pi,pi>dpi;

#define LLINF ((long long) 1e18)//1234567890987654321
#define INF 1234567890ll
// #define cerr if(0)cout
#define MAXN (300006)
int main()
{
	FAST
	ll n,k,l;
	cin>>n>>k>>l;
	string s; cin>>s;
	s='*'+s;
	ll lw=0,up=0;
	FOR(i,1,n)lw+=islower(s[i]), up+=isupper(s[i]);
	auto b=[&](pi x,pi y) {
		if(x.f > y.f || (x.f==y.f&&x.s<y.s)) return 1;
		return 0;
	};
	auto g=[&](pi x,pi y){
		if(x.f > y.f || (x.f==y.f&&x.s>y.s)) return 1;
		return 0;
	};
	vector<ll> lc(n+1, 0);
	auto solve1=[&]() { // min lower case
		vector<pi> dp(n+1, pi(0,0));
		auto bstar_ans=[&](ll x) {
			dp[0] = pi(0, 0);
			deque<spi> dq;
			dq.eb(0,dp[0]);
			FOR(i,1,n) {
				while(dq.size() && i-dq.front().f > l) dq.pop_front();
				if(g(dp[i-1], pi(dq[0].s.f+lc[i]-x,dq[0].s.s+1))) {
					dp[i]=dp[i-1];
				} else {
					dp[i]=pi(dq[0].s.f+lc[i]-x, dq[0].s.s+1);
				}
				while(dq.size() && g(pi(dp[i].f-lc[i],dp[i].s),dq.back().s)) dq.pop_back();
				dq.eb(i, pi(dp[i].f-lc[i],dp[i].s));
			}
			// cerr<<dp[n].f<<' '<<dp[n].s<<'\n';
			return dp[n];
		};
		auto bstar=[&](ll x) {
			dp[0] = pi(0, 0);
			deque<spi> dq;
			dq.eb(0,dp[0]);
			FOR(i,1,n) {
				while(dq.size() && i-dq.front().f > l) dq.pop_front();
				if(b(dp[i-1], pi(dq[0].s.f+lc[i]-x,dq[0].s.s+1))) {
					dp[i]=dp[i-1];
				} else {
					dp[i]=pi(dq[0].s.f+lc[i]-x, dq[0].s.s+1);
				}
				while(dq.size() && b(pi(dp[i].f-lc[i],dp[i].s),dq.back().s)) dq.pop_back();
				dq.eb(i, pi(dp[i].f-lc[i],dp[i].s));
			}
			// cerr<<dp[n].f<<' '<<dp[n].s<<'\n';
			return dp[n];
		};
		ll st=-1,en=n+1,mid=0;
		while(en-st>1) {
			mid=(st+en)>>1;
			if(bstar(mid).s <= k) en=mid;
			else st=mid;
		}
		return bstar_ans(en).f+en*min(bstar_ans(en).s, k);
	};
	FOR(i,1,n) lc[i]=lc[i-1]+islower(s[i]);
	ll ans = lw-solve1();
	FOR(i,1,n) lc[i]=lc[i-1]+isupper(s[i]);
	ans = min(ans, up-solve1());
	cout<<ans<<'\n';
}


#include "bits/stdc++.h"
using namespace std;

#define FAST ios_base::sync_with_stdio(false); cin.tie(0);
#define pb push_back
#define eb emplace_back
#define ins insert
#define ph push
#define f first
#define s second
#define cbr cerr << "hi\n"
#define mmst(x, v) memset((x), v, sizeof ((x)))
#define siz(x) ll(x.size())
#define all(x) (x).begin(), (x).end()
#define lbd(x, y) lower_bound(all(x), y)
#define ubd(x, y) upper_bound(all(x), y)
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());    //can be used by calling rng() or shuffle(A, A+n, rng)
inline long long rand(long long x, long long y) { return (rng() % (y+1-x)) + x; } //inclusivesss
string inline to_string(char c) {string s(1,c);return s;} template<typename T> inline T gcd(T a,T b){ return a==0?llabs(b):gcd(b%a,a); }

typedef long long ll;
typedef long double ld;
#define FOR(i,s,e) for(ll i=s;i<=ll(e);++i)
#define DEC(i,s,e) for(ll i=s;i>=ll(e);--i)
typedef pair<ll,ll>pi; typedef pair<ll,pi>spi; typedef pair<pi,pi>dpi;

#define LLINF ((long long) 1e18)//1234567890987654321
#define INF 1234567890ll
// #define cerr if(0)cout
#define MAXN (300006)
int main()
{
	FAST
	ll n,k,l;
	cin>>n>>k>>l;
	string s; cin>>s;
	s='*'+s;
	ll lw=0,up=0;
	FOR(i,1,n)lw+=bool(islower(s[i])), up+=bool(isupper(s[i]));
	auto b=[&](pi x,pi y) {
		if(x.f > y.f || (x.f==y.f&&x.s<y.s)) return 1;
		return 0;
	};
	auto g=[&](pi x,pi y){
		if(x.f > y.f || (x.f==y.f&&x.s>y.s)) return 1;
		return 0;
	};
	vector<ll> lc(n+1, 0);
	auto solve1=[&]() { // min lower case
		vector<pi> dp(n+1, pi(0,0));
		auto bstar_ans=[&](ll x) {
			dp[0] = pi(0, 0);
			deque<spi> dq;
			dq.eb(0,dp[0]);
			FOR(i,1,n) {
				while(dq.size() && i-dq.front().f > l) dq.pop_front();
				if(g(dp[i-1], pi(dq[0].s.f+lc[i]-x,dq[0].s.s+1))) {
					dp[i]=dp[i-1];
				} else {
					dp[i]=pi(dq[0].s.f+lc[i]-x, dq[0].s.s+1);
				}
				while(dq.size() && g(pi(dp[i].f-lc[i],dp[i].s),dq.back().s)) dq.pop_back();
				dq.eb(i, pi(dp[i].f-lc[i],dp[i].s));
			}
			// cerr<<dp[n].f<<' '<<dp[n].s<<'\n';
			return dp[n];
		};
		auto bstar=[&](ll x) {
			dp[0] = pi(0, 0);
			deque<spi> dq;
			dq.eb(0,dp[0]);
			FOR(i,1,n) {
				while(dq.size() && i-dq.front().f > l) dq.pop_front();
				if(b(dp[i-1], pi(dq[0].s.f+lc[i]-x,dq[0].s.s+1))) {
					dp[i]=dp[i-1];
				} else {
					dp[i]=pi(dq[0].s.f+lc[i]-x, dq[0].s.s+1);
				}
				while(dq.size() && b(pi(dp[i].f-lc[i],dp[i].s),dq.back().s)) dq.pop_back();
				dq.eb(i, pi(dp[i].f-lc[i],dp[i].s));
			}
			// cerr<<dp[n].f<<' '<<dp[n].s<<'\n';
			return dp[n];
		};
		ll st=-1,en=n+1,mid=0;
		while(en-st>1) {
			mid=(st+en)>>1;
			if(bstar(mid).s <= k) en=mid;
			else st=mid;
		}
		return bstar_ans(en).f+en*min(bstar_ans(en).s, k);
	};
	FOR(i,1,n) lc[i]=lc[i-1]+bool(islower(s[i]));
	ll ans = lw-solve1();
	FOR(i,1,n) lc[i]=lc[i-1]+bool(isupper(s[i]));
	ans = min(ans, up-solve1());
	cout<<ans<<'\n';
}


#include <bits/stdc++.h>
#define MOD 998244353
#define DIMN 1000010
using namespace std;
int n , k , l;
priority_queue < pair <int,int> > h;
int a[DIMN] ,b[DIMN] ;
pair <long long,int> dp[DIMN];

pair <long long,int> check (int cst){
    int i;
    for (i=1;i<=n;i++){

        if (i >= l){
            if (dp[i-1].first + a[i] >= dp[i-l].first + l - cst){

                dp[i] = make_pair(dp[i-1].first + a[i] , dp[i-1].second);

            }
            else {

                 dp[i] = make_pair(dp[i-l].first + l - cst , dp[i-l].second + 1);

            }
        }
        else {
            dp[i] = make_pair(dp[i-1].first + a[i] , dp[i-1].second);
        }
    }
    return dp[n];
}

int solve (){
    int st , dr, mid;
    st = 1;
    dr = n;
    while (st <= dr){
        mid = (st + dr)/2;
        if (check(mid).second <= k)
            dr = mid - 1;
        else st = mid + 1;
    }
    return check(st).first + k * st;
}
int main()
{
    FILE *fin = stdin;
    FILE *fout = stdout;
    int i, sol;
    char c;
    fscanf (fin,"%d%d%d\n",&n,&k,&l);
    for (i=1;i<=n;i++){
        c = fgetc (fin);
        if ('A' <= c && c <= 'Z'){
            a[i] = 1;
            /// litera mare
        }
        else {
            b[i] = 1;
        }
    }
    if (k * l > n){
        fprintf (fout,"0");
        return 0;
    }
    /// iei un interval , faci toate 0 -> 1 , suma maxima finala
    sol = solve();
    for (i=1;i<=n;i++){
        a[i] = b[i];
    }
    sol = max(sol , solve());
    fprintf (fout,"%d" , n - sol);
    return 0;
}


#include <bits/stdc++.h>
#define MOD 998244353
#define DIMN 1000010
using namespace std;
int n , k , l;
priority_queue < pair <int,int> > h;
int aint[4 * DIMN] , f[4 * DIMN] , a[DIMN] ,b[DIMN] , sp[DIMN];

inline void lazy_update (int nod,int st,int dr){
    if (!f[nod]) /// nu ii trb lazy
        return;
    if (st<dr){ /// nu e frunza
        f[2*nod]+=f[nod]; /// pass lazy
        f[2*nod+1]+=f[nod];
    }
    aint[nod] = (dr - st + 1);
    f[nod]=0;
}

int query (int nod,int st , int dr , int l ,int r){
    int mid=(st+dr)/2 , sol = 0;
    lazy_update (nod,st,dr);
    if (l<=st && dr<=r){
        return aint[nod];
    }
    if (l<=mid)
        sol += query (2*nod,st,mid,l,r);
    if (mid+1<=r)
        sol += query (2*nod+1,mid+1,dr,l,r);
    lazy_update (2*nod,st,mid);
    lazy_update (2*nod+1,mid+1,dr);
    return sol;
}

void update (int nod,int st ,int dr ,int l , int r){
    int mid=(st+dr)/2;
    lazy_update (nod,st,dr);
    if (l<=st && dr<=r){
        f[nod]++; /// nu ma mai duc in jos
        lazy_update (nod,st,dr);
        return;
    }
    if (l<=mid)
        update (2*nod,st,mid,l,r);
    if (mid+1<=r)
        update (2*nod+1,mid+1,dr,l,r);
    lazy_update (2*nod,st,mid);
    lazy_update (2*nod+1,mid+1,dr);
    aint[nod] = aint[2*nod] + aint[2*nod+1];

}
void build (int nod,int st , int dr){
    int mid = (st + dr)/2;
    f[nod] = 0;
    if (st == dr){
        aint[nod] = a[st];
        return;
    }

    build (2*nod , st , mid);
    build (2 * nod + 1 , mid + 1 , dr);

    aint[nod] = aint[2*nod] + aint[2*nod+1];

}
int solve (){
    int x , sol , sum , inc , s , i;

    while (!h.empty()){
        h.pop();
    }
    build (1 , 1 , n);
    for (i=1;i + l - 1 <= n; i++){
        h.push(make_pair(l - (sp[i + l - 1] - sp[i-1]) , i));
    }

    x = k;
    sol = 0;
    while (x && !h.empty()){
        sum = h.top().first;
        inc = h.top().second;
        h.pop();
        s = query (1,1,n,inc,inc+l-1);
        if ( l - s != sum ){
            h.push(make_pair(l - s , inc));
            continue;
        }
        /// ok
        sol = sol + sum;
        update (1 , 1, n , inc , inc + l - 1);
        x--;
    }

    return sol + sp[n];

}
int main()
{
    FILE *fin = stdin;
    FILE *fout = stdout;
    int i, sol;
    char c;
    fscanf (fin,"%d%d%d\n",&n,&k,&l);
    for (i=1;i<=n;i++){
        c = fgetc (fin);
        if ('A' <= c && c <= 'Z'){
            a[i] = 1;
            /// litera mare
        }
        else {
            b[i] = 1;
        }
    }
    /// iei un interval , faci toate 0 -> 1 , suma maxima finala
    for (i=1;i<=n;i++){
        sp[i] = sp[i-1] + a[i];
    }
    sol = solve();
    for (i=1;i<=n;i++){
        a[i] = b[i];
        sp[i] = sp[i-1] + a[i];
    }
    sol = max(sol , solve());
    fprintf (fout,"%d" , n - sol);
    return 0;
}


#include <bits/stdc++.h>
#define MOD 998244353
#define DIMN 1000010
using namespace std;
int n , k , l;
priority_queue < pair <int,int> > h;
int aint[4 * DIMN] , f[4 * DIMN] , a[DIMN] ,b[DIMN] , sp[DIMN];

inline void lazy_update (int nod,int st,int dr){
    if (!f[nod]) /// nu ii trb lazy
        return;
    if (st<dr){ /// nu e frunza
        f[2*nod]+=f[nod]; /// pass lazy
        f[2*nod+1]+=f[nod];
    }
    aint[nod]+=f[nod] * (dr - st + 1);
    f[nod]=0;
}

int query (int nod,int st , int dr , int l ,int r){
    int mid=(st+dr)/2 , sol = 0;
    lazy_update (nod,st,dr);
    if (l<=st && dr<=r){
        return aint[nod];
    }
    if (l<=mid)
        sol += query (2*nod,st,mid,l,r);
    if (mid+1<=r)
        sol += query (2*nod+1,mid+1,dr,l,r);
    lazy_update (2*nod,st,mid);
    lazy_update (2*nod+1,mid+1,dr);
    return sol;
}

void update (int nod,int st ,int dr ,int l , int r){
    int mid=(st+dr)/2;
    lazy_update (nod,st,dr);
    if (l<=st && dr<=r){
        f[nod]++; /// nu ma mai duc in jos
        lazy_update (nod,st,dr);
        return;
    }
    if (l<=mid)
        update (2*nod,st,mid,l,r);
    if (mid+1<=r)
        update (2*nod+1,mid+1,dr,l,r);
    lazy_update (2*nod,st,mid);
    lazy_update (2*nod+1,mid+1,dr);
    aint[nod] = aint[2*nod] + aint[2*nod+1];

}
void build (int nod,int st , int dr){
    int mid = (st + dr)/2;
    f[nod] = 0;
    if (st == dr){
        aint[nod] = a[st];
        return;
    }

    build (2*nod , st , mid);
    build (2 * nod + 1 , mid + 1 , dr);

    aint[nod] = aint[2*nod] + aint[2*nod+1];

}
int solve (){
    int x , sol , sum , inc , s , i;

    while (!h.empty()){
        h.pop();
    }
    build (1 , 1 , n);
    for (i=1;i + l - 1 <= n; i++){
        h.push(make_pair(l - (sp[i + l - 1] - sp[i-1]) , i));
    }

    x = k;
    sol = 0;
    while (x && !h.empty()){
        sum = h.top().first;
        inc = h.top().second;
        h.pop();
        s = query (1,1,n,inc,inc+l-1);
        if ( l - s != sum ){
            h.push(make_pair(l - s , inc));
            continue;
        }
        /// ok
        sol = sol + sum;
        update (1 , 1, n , inc , inc + l - 1);
        x--;
    }

    return sol + sp[n];

}
int main()
{
    FILE *fin = stdin;
    FILE *fout = stdout;
    int i, sol;
    char c;
    fscanf (fin,"%d%d%d\n",&n,&k,&l);
    for (i=1;i<=n;i++){
        c = fgetc (fin);
        if ('A' <= c && c <= 'Z'){
            a[i] = 1;
            /// litera mare
        }
        else {
            b[i] = 1;
        }
    }
    /// iei un interval , faci toate 0 -> 1 , suma maxima finala
    for (i=1;i<=n;i++){
        sp[i] = sp[i-1] + a[i];
    }
    sol = solve();
    for (i=1;i<=n;i++){
        a[i] = b[i];
        sp[i] = sp[i-1] + a[i];
    }
    sol = max(sol , solve());
    fprintf (fout,"%d" , n - sol);
    return 0;
}


#include <bits/stdc++.h>
#define MOD 998244353
#define DIMN 1000010
using namespace std;
int n , k , l;
priority_queue < pair <int,int> > h;
int aint[4 * DIMN] , f[4 * DIMN] , a[DIMN] ,b[DIMN] , sp[DIMN];

inline void lazy_update (int nod,int st,int dr){
    if (!f[nod]) /// nu ii trb lazy
        return;
    if (st<dr){ /// nu e frunza
        f[2*nod]=f[nod]; /// pass lazy
        f[2*nod+1]=f[nod];
    }
    aint[nod] = (dr - st + 1);
    f[nod]=0;
}

int query (int nod,int st , int dr , int l ,int r){
    int mid=(st+dr)/2 , sol = 0;
    lazy_update (nod,st,dr);
    if (l<=st && dr<=r){
        return aint[nod];
    }
    if (l<=mid)
        sol += query (2*nod,st,mid,l,r);
    if (mid+1<=r)
        sol += query (2*nod+1,mid+1,dr,l,r);
    lazy_update (2*nod,st,mid);
    lazy_update (2*nod+1,mid+1,dr);
    return sol;
}

void update (int nod,int st ,int dr ,int l , int r){
    int mid=(st+dr)/2;
    lazy_update (nod,st,dr);
    if (l<=st && dr<=r){
        f[nod]=1; /// nu ma mai duc in jos
        lazy_update (nod,st,dr);
        return;
    }
    if (l<=mid)
        update (2*nod,st,mid,l,r);
    if (mid+1<=r)
        update (2*nod+1,mid+1,dr,l,r);
    lazy_update (2*nod,st,mid);
    lazy_update (2*nod+1,mid+1,dr);
    aint[nod] = aint[2*nod] + aint[2*nod+1];

}
void build (int nod,int st , int dr){
    int mid = (st + dr)/2;
    f[nod] = 0;
    if (st == dr){
        aint[nod] = a[st];
        return;
    }

    build (2*nod , st , mid);
    build (2 * nod + 1 , mid + 1 , dr);

    aint[nod] = aint[2*nod] + aint[2*nod+1];

}
int solve (){
    int x , sol , sum , inc , s , i;

    while (!h.empty()){
        h.pop();
    }
    build (1 , 1 , n);
    for (i=1;i + l - 1 <= n; i++){
        h.push(make_pair(l - (sp[i + l - 1] - sp[i-1]) , -i));
    }

    x = k;
    sol = 0;
    while (x && !h.empty()){
        sum = h.top().first;
        inc = -h.top().second;
        h.pop();
        s = query (1,1,n,inc,inc+l-1);
        if ( l - s != sum ){
            h.push(make_pair(l - s , -inc));
            continue;
        }
        /// ok
        sol = sol + sum;
        update (1 , 1, n , inc , inc + l - 1);
        x--;
    }

    return sol + sp[n];

}
int main()
{
    FILE *fin = stdin;
    FILE *fout = stdout;
    int i, sol;
    char c;
    fscanf (fin,"%d%d%d\n",&n,&k,&l);
    for (i=1;i<=n;i++){
        c = fgetc (fin);
        if ('A' <= c && c <= 'Z'){
            a[i] = 1;
            /// litera mare
        }
        else {
            b[i] = 1;
        }
    }
    /// iei un interval , faci toate 0 -> 1 , suma maxima finala
    for (i=1;i<=n;i++){
        sp[i] = sp[i-1] + a[i];
    }
    sol = solve();
    for (i=1;i<=n;i++){
        a[i] = b[i];
        sp[i] = sp[i-1] + a[i];
    }
    sol = max(sol , solve());
    fprintf (fout,"%d" , n - sol);
    return 0;
}


#include <bits/stdc++.h>
#define MOD 998244353
#define DIMN 1000010
using namespace std;
int n , k , l;
priority_queue < pair <int,int> > h;
int a[DIMN] ,b[DIMN] ;
pair <long long,int> dp[DIMN];

pair <long long,int> check (int cst){
    int i;
    for (i=1;i<=n;i++){

        if (i >= l){
            if (dp[i-1].first + a[i] >= dp[i-l].first + l - cst){

                dp[i] = make_pair(dp[i-1].first + a[i] , dp[i-1].second);

            }
            else {

                 dp[i] = make_pair(dp[i-l].first + l - cst , dp[i-l].second + 1);

            }
        }
        else {
            dp[i] = make_pair(dp[i-1].first + a[i] , dp[i-1].second);
        }
    }
    return dp[n];
}

int solve (){
    int st , dr, mid;
    st = 1;
    dr = n;
    while (st <= dr){
        mid = (st + dr)/2;
        if (check(mid).second <= k)
            dr = mid - 1;
        else st = mid + 1;
    }
    return check(st).first + k * st;
}
int main()
{
    FILE *fin = stdin;
    FILE *fout = stdout;
    int i, sol;
    char c;
    fscanf (fin,"%d%d%d\n",&n,&k,&l);
    for (i=1;i<=n;i++){
        c = fgetc (fin);
        if ('A' <= c && c <= 'Z'){
            a[i] = 1;
            /// litera mare
        }
        else {
            b[i] = 1;
        }
    }
    if (k * l >= n){
        fprintf (fout,"0");
        return 0;
    }
    /// iei un interval , faci toate 0 -> 1 , suma maxima finala
    sol = solve();
    for (i=1;i<=n;i++){
        a[i] = b[i];
    }
    sol = max(sol , solve());
    fprintf (fout,"%d" , n - sol);
    return 0;
}


#include <bits/stdc++.h>
#define MOD 998244353
#define DIMN 1000010
using namespace std;
int n , k , l;
priority_queue < pair <int,int> > h;
int a[DIMN] ,b[DIMN] ;
pair <long long,int> dp[DIMN];

pair <long long,int> check (int cst){
    int i;
    for (i=1;i<=n;i++){

        if (i >= l){
            if (dp[i-1].first + a[i] >= dp[i-l].first + l - cst){

                dp[i] = make_pair(dp[i-1].first + a[i] , dp[i-1].second);

            }
            else {

                 dp[i] = make_pair(dp[i-l].first + l - cst , dp[i-l].second + 1);

            }
        }
        else {
            dp[i] = make_pair(dp[i-1].first + a[i] , dp[i-1].second);
        }
    }
    return dp[n];
}

int solve (){
    int st , dr, mid;
    st = 1;
    dr = n;
    while (st <= dr){
        mid = (st + dr)/2;
        if (check(mid).second <= k)
            dr = mid - 1;
        else st = mid + 1;
    }
    return check(st).first + k * st;
}
int main()
{
    FILE *fin = stdin;
    FILE *fout = stdout;
    int i, sol;
    char c;
    fscanf (fin,"%d%d%d\n",&n,&k,&l);
    for (i=1;i<=n;i++){
        c = fgetc (fin);
        if ('A' <= c && c <= 'Z'){
            a[i] = 1;
            /// litera mare
        }
        else {
            b[i] = 1;
        }
    }
    /// iei un interval , faci toate 0 -> 1 , suma maxima finala
    sol = solve();
    for (i=1;i<=n;i++){
        a[i] = b[i];
    }
    sol = max(sol , solve());
    fprintf (fout,"%d" , n - sol);
    return 0;
}


#include <bits/stdc++.h>
#define MOD 998244353
#define DIMN 1000010
using namespace std;
long long n , k , l;
priority_queue < pair <long long,long long> > h;
long long a[DIMN] ,b[DIMN] ;
pair <long long,long long> dp[DIMN];

pair <long long,long long> check (long long cst){
    long long i;
    for (i=1;i<=n;i++){

        if (i >= l){
            if (dp[i-1].first + a[i] >= dp[i-l].first + l - cst){

                dp[i] = make_pair(dp[i-1].first + a[i] , dp[i-1].second);

            }
            else {

                 dp[i] = make_pair(dp[i-l].first + l - cst , dp[i-l].second + 1);

            }
        }
        else {
            dp[i] = make_pair(dp[i-1].first + a[i] , dp[i-1].second);
        }
    }
    return dp[n];
}

long long solve (){
    long long st , dr, mid;
    st = 1;
    dr = n;
    while (st <= dr){
        mid = (st + dr)/2;
        if (check(mid).second <= k)
            dr = mid - 1;
        else st = mid + 1;
    }
    return check(st).first + k * st;
}
int main()
{
    FILE *fin = stdin;
    FILE *fout = stdout;
    long long i, sol;
    char c;
    fscanf (fin,"%lld%lld%lld\n",&n,&k,&l);
    for (i=1;i<=n;i++){
        c = fgetc (fin);
        if ('A' <= c && c <= 'Z'){
            a[i] = 1;
            /// litera mare
        }
        else {
            b[i] = 1;
        }
    }
    if (k * l >= n){
        fprintf (fout,"0");
        return 0;
    }
    /// iei un interval , faci toate 0 -> 1 , suma maxima finala
    sol = solve();
    for (i=1;i<=n;i++){
        a[i] = b[i];
    }
    sol = max(sol , solve());
    if (sol > n)
        sol = n;
    fprintf (fout,"%lld" , n - sol);
    return 0;
}


#include <bits/stdc++.h>
#define MOD 998244353
#define DIMN 1000010
using namespace std;
long long n , k , l;
priority_queue < pair <long long,long long> > h;
long long a[DIMN] ,b[DIMN] ;
pair <long long,long long> dp[DIMN];

pair <long long,long long> check (long long cst){
    long long i;
    for (i=1;i<=n;i++){

        if (i >= l){
            if (dp[i-1].first + a[i] >= dp[i-l].first + l - cst){

                dp[i] = make_pair(dp[i-1].first + a[i] , dp[i-1].second);

            }
            else {

                 dp[i] = make_pair(dp[i-l].first + l - cst , dp[i-l].second + 1);

            }
        }
        else {
            dp[i] = make_pair(dp[i-1].first + a[i] , dp[i-1].second);
        }
    }
    return dp[n];
}

long long solve (){
    long long st , dr, mid;
    st = 1;
    dr = n;
    while (st <= dr){
        mid = (st + dr)/2;
        if (check(mid).second <= k)
            dr = mid - 1;
        else st = mid + 1;
    }
    return check(st).first + k * st;
}
int main()
{
    FILE *fin = stdin;
    FILE *fout = stdout;
    long long i, sol;
    char c;
    fscanf (fin,"%lld%lld%lld\n",&n,&k,&l);
    for (i=1;i<=n;i++){
        c = fgetc (fin);
        if ('A' <= c && c <= 'Z'){
            a[i] = 1;
            /// litera mare
        }
        else {
            b[i] = 1;
        }
    }
    if (k * l >= n){
        fprintf (fout,"0");
        return 0;
    }
    /// iei un interval , faci toate 0 -> 1 , suma maxima finala
    sol = solve();
    for (i=1;i<=n;i++){
        a[i] = b[i];
    }
    sol = max(sol , solve());
    fprintf (fout,"%lld" , n - sol);
    return 0;
}


#pragma region
#include <bits/stdc++.h>
using namespace std;
// Common Type shorteners and int128
using ll = long long; using ull = unsigned long long; using ld = long double;
using pii = pair<int, int>; using pll = pair<ll, ll>;
template <typename T> using vec = vector<T>;
template <typename K, typename V> using umap = unordered_map<K, V>; template <typename K> using uset = unordered_set<K>;
using vi = vec<int>; using vl = vec<ll>; using vpi = vec<pii>; using vpl = vec<pll>;
#ifdef __SIZEOF_INT128__
using int128 = __int128_t; using uint128 = __uint128_t;
#endif
template<typename I> string intStr(I x) { string ret; while (x > 0) { ret += (x % 10) + '0'; x /= 10; } reverse(ret.begin(), ret.end()); return ret; } // Int to string
// Shorthand Macros
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f3f
#define mpr make_pair
#define pb push_back
#define popcount __builtin_popcount
#define clz __builtin_clz
#define ctz __builtin_ctz
// Shorthand Function Macros
#define sz(x) ((int)((x).size()))
#define all(x) (x).begin(), (x).end()
#define rep(i, a, b) for (__typeof(a) i = a; i < b; i++)
#define reprev(i, a, b) for (__typeof(a) i = a; i > b; i--)
#define repi(a, b) rep(i, a, b)
#define repj(a, b) rep(j, a, b)
#define repk(a, b) rep(k, a, b)
#define Cmplt(type) bool operator<(const type &o) const
#define Cmpgt(type) bool operator>(const type &o) const
#define Cmpfn(name, type) bool name(const type &a, const type &b)
#define Inop(type) istream& operator>>(istream& in, type &o)
#define Outop(type) ostream& operator<<(ostream& out, type o)
#define Pow2(x) (1LL << (x))
#define scn(type, ...) type __VA_ARGS__; scan(__VA_ARGS__) // scn -> Short for SCan New
// Shorthand Functions
template<typename T> inline void maxa(T& st, T v) { st = max(st, v); }
template<typename T> inline void mina(T& st, T v) { st = min(st, v); }
inline void setprec(ostream& out, int prec) { out << setprecision(prec) << fixed; }
// Out operators and printing for arrays and vectors
template <typename T> ostream& operator<<(ostream& out,vector<T> iter){out<<"[";for(auto t:iter){out<<t<<", ";}out<<"]";return out;}
template <typename T> string arrayStr(T *arr,int sz){string ret = "[";for(int i=0;i<sz;i++){ret+=to_string(arr[i])+", "; } return ret + "]";}
template <typename T> void printArray(T *arr,int sz){for(int i=0;i<sz;i++){cout<<arr[i]<<" "; } cout<<"\n";}
// I/O Operations
inline void scan(){}
template<typename F, typename... R> inline void scan(F &f,R&... r){cin>>f;scan(r...);}
template <typename F> inline void println(F t){cout<<t<<'\n';}
template<typename F, typename... R> inline void println(F f,R... r){cout<<f<<" ";println(r...);}
inline void print(){}
template<typename F, typename... R> inline void print(F f,R... r){cout<<f;print(r...);}
// Debugging
#define db(x) cout << (#x) << ": " << x << ", "
#define dblb(s) cout << "[" << s << "] "
#define dbbin(x, n) cout << (#x) << ": " << bitset<n>(x) << ", "
#define dbarr(x, n) cout << (#x) << ": " << arrayStr((x), (n)) << ", "
#define dbln cout << endl;
#pragma endregion

const ld EPS = 1e-15;
const int MN = 1e6 + 1;
int n, k, len;
string s;
bool up[MN];

// dp
using pdi = pair<ld, int>; // best, number of use

ll pfx[MN];
pdi dp[MN];

ll rsq(int l, int r) {
    return pfx[r] - pfx[l - 1];
}

pdi runDP(ld C) {
    // db(C); db(pfx[n]); dbln;

    deque<int> Q; Q.pb(0);
    dp[0] = {0, 0};
    repi(1, n + 1) {
        while (!Q.empty() && Q.front() < i - len)
            Q.pop_front();

        pdi best = dp[i - 1];
        best.first += up[i];
        ld alt = dp[Q.front()].first + C;
        if (alt < best.first) {
            best.first = alt;
            best.second = dp[Q.front()].second + 1;
        }

        dp[i] = best;

        while (!Q.empty() && dp[Q.back()].first > best.first)
            Q.pop_back();
        Q.pb(i);

        // db(i); db(best.first); db(best.second); dbln;
    }

    return dp[n];
}

int solve() {
    repi(1, n + 1)
        pfx[i] = pfx[i - 1] + up[i];

    double l = 0, r = n;
    while (l + EPS < r) {
        double mid = (l + r) / 2.;
        auto tans = runDP(mid);

        if (tans.second <= k)
            r = mid;
        else
            l = mid;
    }

    auto ans = runDP(r);
    // assert(ans.second == k);
    // db(r); dbln;
    return (int)(round(ans.first - k * r));
}

int main(){
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    scan(n, k, len, s);

    repi(1, n + 1)
        up[i] = isupper(s[i - 1]) != 0;

    // do and flip
    int best = solve();
    repi(1, n + 1)
        up[i] ^= 1;
    // dblb("tolow"); db(best); dbln;
    // dblb("-------------------------"); dbln;
    mina(best, solve());
    println(best);

    return 0;
}


#pragma region
#include <bits/stdc++.h>
using namespace std;
// Common Type shorteners and int128
using ll = long long; using ull = unsigned long long; using ld = long double;
using pii = pair<int, int>; using pll = pair<ll, ll>;
template <typename T> using vec = vector<T>;
template <typename K, typename V> using umap = unordered_map<K, V>; template <typename K> using uset = unordered_set<K>;
using vi = vec<int>; using vl = vec<ll>; using vpi = vec<pii>; using vpl = vec<pll>;
#ifdef __SIZEOF_INT128__
using int128 = __int128_t; using uint128 = __uint128_t;
#endif
template<typename I> string intStr(I x) { string ret; while (x > 0) { ret += (x % 10) + '0'; x /= 10; } reverse(ret.begin(), ret.end()); return ret; } // Int to string
// Shorthand Macros
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f3f
#define mpr make_pair
#define pb push_back
#define popcount __builtin_popcount
#define clz __builtin_clz
#define ctz __builtin_ctz
// Shorthand Function Macros
#define sz(x) ((int)((x).size()))
#define all(x) (x).begin(), (x).end()
#define rep(i, a, b) for (__typeof(a) i = a; i < b; i++)
#define reprev(i, a, b) for (__typeof(a) i = a; i > b; i--)
#define repi(a, b) rep(i, a, b)
#define repj(a, b) rep(j, a, b)
#define repk(a, b) rep(k, a, b)
#define Cmplt(type) bool operator<(const type &o) const
#define Cmpgt(type) bool operator>(const type &o) const
#define Cmpfn(name, type) bool name(const type &a, const type &b)
#define Inop(type) istream& operator>>(istream& in, type &o)
#define Outop(type) ostream& operator<<(ostream& out, type o)
#define Pow2(x) (1LL << (x))
#define scn(type, ...) type __VA_ARGS__; scan(__VA_ARGS__) // scn -> Short for SCan New
// Shorthand Functions
template<typename T> inline void maxa(T& st, T v) { st = max(st, v); }
template<typename T> inline void mina(T& st, T v) { st = min(st, v); }
inline void setprec(ostream& out, int prec) { out << setprecision(prec) << fixed; }
// Out operators and printing for arrays and vectors
template <typename T> ostream& operator<<(ostream& out,vector<T> iter){out<<"[";for(auto t:iter){out<<t<<", ";}out<<"]";return out;}
template <typename T> string arrayStr(T *arr,int sz){string ret = "[";for(int i=0;i<sz;i++){ret+=to_string(arr[i])+", "; } return ret + "]";}
template <typename T> void printArray(T *arr,int sz){for(int i=0;i<sz;i++){cout<<arr[i]<<" "; } cout<<"\n";}
// I/O Operations
inline void scan(){}
template<typename F, typename... R> inline void scan(F &f,R&... r){cin>>f;scan(r...);}
template <typename F> inline void println(F t){cout<<t<<'\n';}
template<typename F, typename... R> inline void println(F f,R... r){cout<<f<<" ";println(r...);}
inline void print(){}
template<typename F, typename... R> inline void print(F f,R... r){cout<<f;print(r...);}
// Debugging
#define db(x) cout << (#x) << ": " << x << ", "
#define dblb(s) cout << "[" << s << "] "
#define dbbin(x, n) cout << (#x) << ": " << bitset<n>(x) << ", "
#define dbarr(x, n) cout << (#x) << ": " << arrayStr((x), (n)) << ", "
#define dbln cout << endl;
#pragma endregion

const ld EPS = 1e-6;
const int MN = 1e6 + 1;
int n, k, len;
string s;
bool up[MN];

// dp
using pdi = pair<ld, int>; // best, number of use

ll pfx[MN];
pdi dp[MN];

ll rsq(int l, int r) {
    return pfx[r] - pfx[l - 1];
}

pdi runDP(ld C) {
    // db(C); db(pfx[n]); dbln;

    deque<int> Q; Q.pb(0);
    dp[0] = {0, 0};
    repi(1, n + 1) {
        while (!Q.empty() && Q.front() < i - len)
            Q.pop_front();

        pdi best = dp[i - 1];
        best.first += up[i];
        ld alt = dp[Q.front()].first + C;
        if (alt < best.first) {
            best.first = alt;
            best.second = dp[Q.front()].second + 1;
        }

        dp[i] = best;

        while (!Q.empty() && dp[Q.back()].first > best.first)
            Q.pop_back();
        Q.pb(i);

        // db(i); db(best.first); db(best.second); dbln;
    }

    return dp[n];
}

int solve() {
    repi(1, n + 1)
        pfx[i] = pfx[i - 1] + up[i];

    double l = 0, r = n;
    while (l + EPS < r) {
        double mid = (l + r) / 2.;
        auto tans = runDP(mid);

        if (tans.second <= k)
            r = mid;
        else
            l = mid;
    }

    auto ans = runDP(r);
    // assert(ans.second == k);
    // db(r); dbln;
    return (int)(round(ans.first - k * r));
}

int main(){
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    scan(n, k, len, s);

    repi(1, n + 1)
        up[i] = isupper(s[i - 1]) != 0;

    // do and flip
    int best = solve();
    repi(1, n + 1)
        up[i] ^= 1;
    // dblb("tolow"); db(best); dbln;
    // dblb("-------------------------"); dbln;
    mina(best, solve());
    println(best);

    return 0;
}


#pragma region
#include <bits/stdc++.h>
using namespace std;
// Common Type shorteners and int128
using ll = long long; using ull = unsigned long long; using ld = long double;
using pii = pair<int, int>; using pll = pair<ll, ll>;
template <typename T> using vec = vector<T>;
template <typename K, typename V> using umap = unordered_map<K, V>; template <typename K> using uset = unordered_set<K>;
using vi = vec<int>; using vl = vec<ll>; using vpi = vec<pii>; using vpl = vec<pll>;
#ifdef __SIZEOF_INT128__
using int128 = __int128_t; using uint128 = __uint128_t;
#endif
template<typename I> string intStr(I x) { string ret; while (x > 0) { ret += (x % 10) + '0'; x /= 10; } reverse(ret.begin(), ret.end()); return ret; } // Int to string
// Shorthand Macros
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f3f
#define mpr make_pair
#define pb push_back
#define popcount __builtin_popcount
#define clz __builtin_clz
#define ctz __builtin_ctz
// Shorthand Function Macros
#define sz(x) ((int)((x).size()))
#define all(x) (x).begin(), (x).end()
#define rep(i, a, b) for (__typeof(a) i = a; i < b; i++)
#define reprev(i, a, b) for (__typeof(a) i = a; i > b; i--)
#define repi(a, b) rep(i, a, b)
#define repj(a, b) rep(j, a, b)
#define repk(a, b) rep(k, a, b)
#define Cmplt(type) bool operator<(const type &o) const
#define Cmpgt(type) bool operator>(const type &o) const
#define Cmpfn(name, type) bool name(const type &a, const type &b)
#define Inop(type) istream& operator>>(istream& in, type &o)
#define Outop(type) ostream& operator<<(ostream& out, type o)
#define Pow2(x) (1LL << (x))
#define scn(type, ...) type __VA_ARGS__; scan(__VA_ARGS__) // scn -> Short for SCan New
// Shorthand Functions
template<typename T> inline void maxa(T& st, T v) { st = max(st, v); }
template<typename T> inline void mina(T& st, T v) { st = min(st, v); }
inline void setprec(ostream& out, int prec) { out << setprecision(prec) << fixed; }
// Out operators and printing for arrays and vectors
template <typename T> ostream& operator<<(ostream& out,vector<T> iter){out<<"[";for(auto t:iter){out<<t<<", ";}out<<"]";return out;}
template <typename T> string arrayStr(T *arr,int sz){string ret = "[";for(int i=0;i<sz;i++){ret+=to_string(arr[i])+", "; } return ret + "]";}
template <typename T> void printArray(T *arr,int sz){for(int i=0;i<sz;i++){cout<<arr[i]<<" "; } cout<<"\n";}
// I/O Operations
inline void scan(){}
template<typename F, typename... R> inline void scan(F &f,R&... r){cin>>f;scan(r...);}
template <typename F> inline void println(F t){cout<<t<<'\n';}
template<typename F, typename... R> inline void println(F f,R... r){cout<<f<<" ";println(r...);}
inline void print(){}
template<typename F, typename... R> inline void print(F f,R... r){cout<<f;print(r...);}
// Debugging
#define db(x) cout << (#x) << ": " << x << ", "
#define dblb(s) cout << "[" << s << "] "
#define dbbin(x, n) cout << (#x) << ": " << bitset<n>(x) << ", "
#define dbarr(x, n) cout << (#x) << ": " << arrayStr((x), (n)) << ", "
#define dbln cout << endl;
#pragma endregion

const ld EPS = 1e-12;
const int MN = 1e6 + 1;
int n, k, len;
string s;
bool up[MN];

// dp
using pdi = pair<ld, int>; // best, number of use

ll pfx[MN];
pdi dp[MN];

ll rsq(int l, int r) {
    return pfx[r] - pfx[l - 1];
}

pdi runDP(ld C) {
    // db(C); db(pfx[n]); dbln;

    deque<int> Q; Q.pb(0);
    dp[0] = {0, 0};
    repi(1, n + 1) {
        while (!Q.empty() && Q.front() < i - len)
            Q.pop_front();

        pdi best = dp[i - 1];
        best.first += up[i];
        ld alt = dp[Q.front()].first + C;
        if (alt < best.first) {
            best.first = alt;
            best.second = dp[Q.front()].second + 1;
        }

        dp[i] = best;

        while (!Q.empty() && dp[Q.back()].first > best.first)
            Q.pop_back();
        Q.pb(i);

        // db(i); db(best.first); db(best.second); dbln;
    }

    return dp[n];
}

int solve() {
    repi(1, n + 1)
        pfx[i] = pfx[i - 1] + up[i];

    double l = 0, r = n;
    while (l + EPS < r) {
        double mid = (l + r) / 2.;
        auto tans = runDP(mid);

        if (tans.second <= k)
            r = mid;
        else
            l = mid;
    }

    auto ans = runDP(r);
    // assert(ans.second == k);
    // db(r); dbln;
    return (int)(round(ans.first - k * r));
}

int main(){
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    scan(n, k, len, s);

    repi(1, n + 1)
        up[i] = isupper(s[i - 1]) != 0;

    // do and flip
    int best = solve();
    repi(1, n + 1)
        up[i] ^= 1;
    // dblb("tolow"); db(best); dbln;
    // dblb("-------------------------"); dbln;
    mina(best, solve());
    println(best);

    return 0;
}


#pragma region
#include <bits/stdc++.h>
using namespace std;
// Common Type shorteners and int128
using ll = long long; using ull = unsigned long long; using ld = long double;
using pii = pair<int, int>; using pll = pair<ll, ll>;
template <typename T> using vec = vector<T>;
template <typename K, typename V> using umap = unordered_map<K, V>; template <typename K> using uset = unordered_set<K>;
using vi = vec<int>; using vl = vec<ll>; using vpi = vec<pii>; using vpl = vec<pll>;
#ifdef __SIZEOF_INT128__
using int128 = __int128_t; using uint128 = __uint128_t;
#endif
template<typename I> string intStr(I x) { string ret; while (x > 0) { ret += (x % 10) + '0'; x /= 10; } reverse(ret.begin(), ret.end()); return ret; } // Int to string
// Shorthand Macros
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f3f
#define mpr make_pair
#define pb push_back
#define popcount __builtin_popcount
#define clz __builtin_clz
#define ctz __builtin_ctz
// Shorthand Function Macros
#define sz(x) ((int)((x).size()))
#define all(x) (x).begin(), (x).end()
#define rep(i, a, b) for (__typeof(a) i = a; i < b; i++)
#define reprev(i, a, b) for (__typeof(a) i = a; i > b; i--)
#define repi(a, b) rep(i, a, b)
#define repj(a, b) rep(j, a, b)
#define repk(a, b) rep(k, a, b)
#define Cmplt(type) bool operator<(const type &o) const
#define Cmpgt(type) bool operator>(const type &o) const
#define Cmpfn(name, type) bool name(const type &a, const type &b)
#define Inop(type) istream& operator>>(istream& in, type &o)
#define Outop(type) ostream& operator<<(ostream& out, type o)
#define Pow2(x) (1LL << (x))
#define scn(type, ...) type __VA_ARGS__; scan(__VA_ARGS__) // scn -> Short for SCan New
// Shorthand Functions
template<typename T> inline void maxa(T& st, T v) { st = max(st, v); }
template<typename T> inline void mina(T& st, T v) { st = min(st, v); }
inline void setprec(ostream& out, int prec) { out << setprecision(prec) << fixed; }
// Out operators and printing for arrays and vectors
template <typename T> ostream& operator<<(ostream& out,vector<T> iter){out<<"[";for(auto t:iter){out<<t<<", ";}out<<"]";return out;}
template <typename T> string arrayStr(T *arr,int sz){string ret = "[";for(int i=0;i<sz;i++){ret+=to_string(arr[i])+", "; } return ret + "]";}
template <typename T> void printArray(T *arr,int sz){for(int i=0;i<sz;i++){cout<<arr[i]<<" "; } cout<<"\n";}
// I/O Operations
inline void scan(){}
template<typename F, typename... R> inline void scan(F &f,R&... r){cin>>f;scan(r...);}
template <typename F> inline void println(F t){cout<<t<<'\n';}
template<typename F, typename... R> inline void println(F f,R... r){cout<<f<<" ";println(r...);}
inline void print(){}
template<typename F, typename... R> inline void print(F f,R... r){cout<<f;print(r...);}
// Debugging
#define db(x) cout << (#x) << ": " << x << ", "
#define dblb(s) cout << "[" << s << "] "
#define dbbin(x, n) cout << (#x) << ": " << bitset<n>(x) << ", "
#define dbarr(x, n) cout << (#x) << ": " << arrayStr((x), (n)) << ", "
#define dbln cout << endl;
#pragma endregion

const int MN = 2e6 + 1;
int n, k, len;
string s;
bool up[MN];

// ds
pii seg[MN << 2];
int lazy[MN << 3], initPfx[MN];
set<int> uppers;

// pair<int, int> -> (val, index)
inline void updLazy(int i) {
    if (lazy[i]) {
        seg[i].first += lazy[i];
        lazy[i << 1] += lazy[i];
        lazy[i << 1 | 1] += lazy[i];
        lazy[i] = 0;
    }
}

pii build(int i, int l, int r){
    if(l == r) return seg[i] = {initPfx[l + len - 1] - initPfx[l - 1], l};
    int mid = (l + r) >> 1;
    return seg[i] = max(build(i << 1, l, mid), build(i << 1 | 1, mid + 1, r));
}

pii update(int i, int bl, int br, int ql, int qr){
    updLazy(i);
    if(qr < bl || ql > br) return seg[i];
    if(bl >= ql && br <= qr) {
        lazy[i]--;
        updLazy(i);
        return seg[i];
    }
    int mid = (bl + br) >> 1;
    return seg[i] = max(update(i << 1, bl, mid, ql, qr), update(i << 1 | 1, mid + 1, br, ql, qr));
    // db(i); db(bl); db(br); db(ql); db(qr); db(seg[i].first); db(seg[i].second); dbln;
    // return seg[i];
}

int solve() {
    // reset ds
    repi(1, n + 1)
        initPfx[i] = initPfx[i - 1] + up[i];

    uppers.clear();
    repi(1, n + 1)
        if (up[i])
            uppers.insert(i);

#define ALL 1, 1, sz
    int sz = n - len + 1;
    build(1, 1, sz);
    // memset(lazy, 0, sizeof lazy);
    fill(lazy, lazy + (MN << 3), 0);

    // start doin shit
    repi(0, k) {
        if (uppers.empty()) break;

        updLazy(1);
        int mx = seg[1].second;

        // db(i); dbln;
        // for (auto x : uppers)
        //     db(x);
        // dbln;
        // db(mx); dbln;

        auto ptr = uppers.lower_bound(mx), ptr2 = uppers.upper_bound(mx + len - 1);
        for (auto it = ptr; it != ptr2; it++) {
            int l = max(1, *it - len + 1), r = min(*it, sz);
            if (l <= r)
                update(ALL, l, r);
            // dblb("rem"); db(*it); dbln;
        }
        uppers.erase(ptr, ptr2);
    }

    return uppers.size();
#undef ALL
}

int main(){
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    scan(n, k, len, s);

    repi(1, n + 1)
        up[i] = isupper(s[i - 1]) != 0;

    // n = 1000000;
    // k = 1000000;
    // len = 1;
    // repi(1, n + 1)
    //     up[i] = i & 1;

    // do and flip
    int best = solve();
    repi(1, n + 1)
        up[i] ^= 1;
    // dblb("tolow"); db(best); dbln;
    // dblb("-------------------------"); dbln;
    mina(best, solve());
    println(best);

    return 0;
}


#pragma region
#include <bits/stdc++.h>
using namespace std;
// Common Type shorteners and int128
using ll = long long; using ull = unsigned long long; using ld = long double;
using pii = pair<int, int>; using pll = pair<ll, ll>;
template <typename T> using vec = vector<T>;
template <typename K, typename V> using umap = unordered_map<K, V>; template <typename K> using uset = unordered_set<K>;
using vi = vec<int>; using vl = vec<ll>; using vpi = vec<pii>; using vpl = vec<pll>;
#ifdef __SIZEOF_INT128__
using int128 = __int128_t; using uint128 = __uint128_t;
#endif
template<typename I> string intStr(I x) { string ret; while (x > 0) { ret += (x % 10) + '0'; x /= 10; } reverse(ret.begin(), ret.end()); return ret; } // Int to string
// Shorthand Macros
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f3f
#define mpr make_pair
#define pb push_back
#define popcount __builtin_popcount
#define clz __builtin_clz
#define ctz __builtin_ctz
// Shorthand Function Macros
#define sz(x) ((int)((x).size()))
#define all(x) (x).begin(), (x).end()
#define rep(i, a, b) for (__typeof(a) i = a; i < b; i++)
#define reprev(i, a, b) for (__typeof(a) i = a; i > b; i--)
#define repi(a, b) rep(i, a, b)
#define repj(a, b) rep(j, a, b)
#define repk(a, b) rep(k, a, b)
#define Cmplt(type) bool operator<(const type &o) const
#define Cmpgt(type) bool operator>(const type &o) const
#define Cmpfn(name, type) bool name(const type &a, const type &b)
#define Inop(type) istream& operator>>(istream& in, type &o)
#define Outop(type) ostream& operator<<(ostream& out, type o)
#define Pow2(x) (1LL << (x))
#define scn(type, ...) type __VA_ARGS__; scan(__VA_ARGS__) // scn -> Short for SCan New
// Shorthand Functions
template<typename T> inline void maxa(T& st, T v) { st = max(st, v); }
template<typename T> inline void mina(T& st, T v) { st = min(st, v); }
inline void setprec(ostream& out, int prec) { out << setprecision(prec) << fixed; }
// Out operators and printing for arrays and vectors
template <typename T> ostream& operator<<(ostream& out,vector<T> iter){out<<"[";for(auto t:iter){out<<t<<", ";}out<<"]";return out;}
template <typename T> string arrayStr(T *arr,int sz){string ret = "[";for(int i=0;i<sz;i++){ret+=to_string(arr[i])+", "; } return ret + "]";}
template <typename T> void printArray(T *arr,int sz){for(int i=0;i<sz;i++){cout<<arr[i]<<" "; } cout<<"\n";}
// I/O Operations
inline void scan(){}
template<typename F, typename... R> inline void scan(F &f,R&... r){cin>>f;scan(r...);}
template <typename F> inline void println(F t){cout<<t<<'\n';}
template<typename F, typename... R> inline void println(F f,R... r){cout<<f<<" ";println(r...);}
inline void print(){}
template<typename F, typename... R> inline void print(F f,R... r){cout<<f;print(r...);}
// Debugging
#define db(x) cout << (#x) << ": " << x << ", "
#define dblb(s) cout << "[" << s << "] "
#define dbbin(x, n) cout << (#x) << ": " << bitset<n>(x) << ", "
#define dbarr(x, n) cout << (#x) << ": " << arrayStr((x), (n)) << ", "
#define dbln cout << endl;
#pragma endregion

const int MN = 1e6 + 1;
int n, k, len;
string s;
bool up[MN];

// ds
pii seg[MN << 2];
int lazy[MN << 3], initPfx[MN];
set<int> uppers;

// pair<int, int> -> (val, index)
inline void updLazy(int i) {
    if (lazy[i]) {
        seg[i].first += lazy[i];
        lazy[i << 1] += lazy[i];
        lazy[i << 1 | 1] += lazy[i];
        lazy[i] = 0;
    }
}

pii build(int i, int l, int r){
    if(l == r) return seg[i] = {initPfx[l + len - 1] - initPfx[l - 1], l};
    int mid = (l + r) >> 1;
    return seg[i] = max(build(i << 1, l, mid), build(i << 1 | 1, mid + 1, r));
}

pii query(int i, int bl, int br, int ql, int qr){
    updLazy(i);
    if(br < ql || bl > qr) return {-INF, -1};
    if(bl >= ql && br <= qr) return seg[i];

    int mid = (bl + br) >> 1;
    return max(query(i << 1, bl, mid, ql, qr), query(i << 1 | 1, mid + 1, br, ql, qr));
}

pii update(int i, int bl, int br, int ql, int qr, int v){
    updLazy(i);
    if(qr < bl || ql > br) return seg[i];
    if(bl >= ql && br <= qr) {
        lazy[i] = v;
        updLazy(i);
        return seg[i];
    }
    int mid = (bl + br) >> 1;
    return seg[i] = max(update(i << 1, bl, mid, ql, qr, v), update(i << 1 | 1, mid + 1, br, ql, qr, v));
    // db(i); db(bl); db(br); db(ql); db(qr); db(seg[i].first); db(seg[i].second); dbln;
    // return seg[i];
}

int solve() {
    // reset ds
    repi(1, n + 1)
        initPfx[i] = initPfx[i - 1] + up[i];

    uppers.clear();
    repi(1, n + 1)
        if (up[i])
            uppers.insert(i);

#define ALL 1, 1, sz
    int sz = n - len + 1;
    build(1, 1, sz);
    memset(lazy, 0, sizeof lazy);

    // start doin shit
    repi(0, k) {
        if (uppers.empty()) break;

        int mx = query(ALL, 1, sz).second;

        // db(i); dbln;
        // for (auto x : uppers)
        //     db(x);
        // dbln;
        // db(mx); dbln;

        auto ptr = uppers.lower_bound(mx), ptr2 = uppers.upper_bound(mx + len - 1);
        for (auto it = ptr; it != ptr2; it++) {
            update(ALL, max(1, *it - len + 1), *it, -1);
            // dblb("rem"); db(*it); dbln;
        }
        uppers.erase(ptr, ptr2);
    }

    return uppers.size();
#undef ALL
}

int main(){
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    scan(n, k, len, s);

    repi(1, n + 1)
        up[i] = isupper(s[i - 1]);

    // do and flip
    int best = solve();
    repi(1, n + 1)
        up[i] ^= 1;
    // dblb("-------------------------"); dbln;
    mina(best, solve());
    println(best);

    return 0;
}


#pragma region
#include <bits/stdc++.h>
using namespace std;
// Common Type shorteners and int128
using ll = long long; using ull = unsigned long long; using ld = long double;
using pii = pair<int, int>; using pll = pair<ll, ll>;
template <typename T> using vec = vector<T>;
template <typename K, typename V> using umap = unordered_map<K, V>; template <typename K> using uset = unordered_set<K>;
using vi = vec<int>; using vl = vec<ll>; using vpi = vec<pii>; using vpl = vec<pll>;
#ifdef __SIZEOF_INT128__
using int128 = __int128_t; using uint128 = __uint128_t;
#endif
template<typename I> string intStr(I x) { string ret; while (x > 0) { ret += (x % 10) + '0'; x /= 10; } reverse(ret.begin(), ret.end()); return ret; } // Int to string
// Shorthand Macros
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f3f
#define mpr make_pair
#define pb push_back
#define popcount __builtin_popcount
#define clz __builtin_clz
#define ctz __builtin_ctz
// Shorthand Function Macros
#define sz(x) ((int)((x).size()))
#define all(x) (x).begin(), (x).end()
#define rep(i, a, b) for (__typeof(a) i = a; i < b; i++)
#define reprev(i, a, b) for (__typeof(a) i = a; i > b; i--)
#define repi(a, b) rep(i, a, b)
#define repj(a, b) rep(j, a, b)
#define repk(a, b) rep(k, a, b)
#define Cmplt(type) bool operator<(const type &o) const
#define Cmpgt(type) bool operator>(const type &o) const
#define Cmpfn(name, type) bool name(const type &a, const type &b)
#define Inop(type) istream& operator>>(istream& in, type &o)
#define Outop(type) ostream& operator<<(ostream& out, type o)
#define Pow2(x) (1LL << (x))
#define scn(type, ...) type __VA_ARGS__; scan(__VA_ARGS__) // scn -> Short for SCan New
// Shorthand Functions
template<typename T> inline void maxa(T& st, T v) { st = max(st, v); }
template<typename T> inline void mina(T& st, T v) { st = min(st, v); }
inline void setprec(ostream& out, int prec) { out << setprecision(prec) << fixed; }
// Out operators and printing for arrays and vectors
template <typename T> ostream& operator<<(ostream& out,vector<T> iter){out<<"[";for(auto t:iter){out<<t<<", ";}out<<"]";return out;}
template <typename T> string arrayStr(T *arr,int sz){string ret = "[";for(int i=0;i<sz;i++){ret+=to_string(arr[i])+", "; } return ret + "]";}
template <typename T> void printArray(T *arr,int sz){for(int i=0;i<sz;i++){cout<<arr[i]<<" "; } cout<<"\n";}
// I/O Operations
inline void scan(){}
template<typename F, typename... R> inline void scan(F &f,R&... r){cin>>f;scan(r...);}
template <typename F> inline void println(F t){cout<<t<<'\n';}
template<typename F, typename... R> inline void println(F f,R... r){cout<<f<<" ";println(r...);}
inline void print(){}
template<typename F, typename... R> inline void print(F f,R... r){cout<<f;print(r...);}
// Debugging
#define db(x) cout << (#x) << ": " << x << ", "
#define dblb(s) cout << "[" << s << "] "
#define dbbin(x, n) cout << (#x) << ": " << bitset<n>(x) << ", "
#define dbarr(x, n) cout << (#x) << ": " << arrayStr((x), (n)) << ", "
#define dbln cout << endl;
#pragma endregion

const int MN = 2e6 + 1;
int n, k, len;
string s;
bool up[MN];

// ds
pii seg[MN << 2];
int lazy[MN << 3], initPfx[MN];
set<int> uppers;

// pair<int, int> -> (val, index)
inline void updLazy(int i) {
    if (lazy[i]) {
        seg[i].first += lazy[i];
        lazy[i << 1] += lazy[i];
        lazy[i << 1 | 1] += lazy[i];
        lazy[i] = 0;
    }
}

pii build(int i, int l, int r){
    if(l == r) return seg[i] = {initPfx[l + len - 1] - initPfx[l - 1], l};
    int mid = (l + r) >> 1;
    return seg[i] = max(build(i << 1, l, mid), build(i << 1 | 1, mid + 1, r));
}

pii query(int i, int bl, int br, int ql, int qr){
    updLazy(i);
    if(br < ql || bl > qr) return {-INF, -1};
    if(bl >= ql && br <= qr) return seg[i];

    int mid = (bl + br) >> 1;
    return max(query(i << 1, bl, mid, ql, qr), query(i << 1 | 1, mid + 1, br, ql, qr));
}

pii update(int i, int bl, int br, int ql, int qr){
    updLazy(i);
    if(qr < bl || ql > br) return seg[i];
    if(bl >= ql && br <= qr) {
        lazy[i] = -1;
        updLazy(i);
        return seg[i];
    }
    int mid = (bl + br) >> 1;
    return seg[i] = max(update(i << 1, bl, mid, ql, qr), update(i << 1 | 1, mid + 1, br, ql, qr));
    // db(i); db(bl); db(br); db(ql); db(qr); db(seg[i].first); db(seg[i].second); dbln;
    // return seg[i];
}

int solve() {
    // reset ds
    repi(1, n + 1)
        initPfx[i] = initPfx[i - 1] + up[i];

    uppers.clear();
    repi(1, n + 1)
        if (up[i])
            uppers.insert(i);

#define ALL 1, 1, sz
    int sz = n - len + 1;
    build(1, 1, sz);
    memset(lazy, 0, sizeof lazy);

    // start doin shit
    repi(0, k) {
        if (uppers.empty()) break;

        int mx = query(ALL, 1, sz).second;

        // db(i); dbln;
        // for (auto x : uppers)
        //     db(x);
        // dbln;
        // db(mx); dbln;

        auto ptr = uppers.lower_bound(mx), ptr2 = uppers.upper_bound(mx + len - 1);
        for (auto it = ptr; it != ptr2; it++) {
            update(ALL, max(1, *it - len + 1), *it);
            // dblb("rem"); db(*it); dbln;
        }
        uppers.erase(ptr, ptr2);
    }

    return uppers.size();
#undef ALL
}

int main(){
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    scan(n, k, len, s);

    repi(1, n + 1)
        up[i] = isupper(s[i - 1]);

    // n = 1000000;
    // k = 1000000;
    // len = 1;
    // repi(1, n + 1)
    //     up[i] = i & 1;

    // do and flip
    int best = solve();
    repi(1, n + 1)
        up[i] ^= 1;
    // dblb("tolow"); db(best); dbln;
    // dblb("-------------------------"); dbln;
    mina(best, solve());
    println(best);

    return 0;
}


#pragma region
#include <bits/stdc++.h>
using namespace std;
// Common Type shorteners and int128
using ll = long long; using ull = unsigned long long; using ld = long double;
using pii = pair<int, int>; using pll = pair<ll, ll>;
template <typename T> using vec = vector<T>;
template <typename K, typename V> using umap = unordered_map<K, V>; template <typename K> using uset = unordered_set<K>;
using vi = vec<int>; using vl = vec<ll>; using vpi = vec<pii>; using vpl = vec<pll>;
#ifdef __SIZEOF_INT128__
using int128 = __int128_t; using uint128 = __uint128_t;
#endif
template<typename I> string intStr(I x) { string ret; while (x > 0) { ret += (x % 10) + '0'; x /= 10; } reverse(ret.begin(), ret.end()); return ret; } // Int to string
// Shorthand Macros
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f3f
#define mpr make_pair
#define pb push_back
#define popcount __builtin_popcount
#define clz __builtin_clz
#define ctz __builtin_ctz
// Shorthand Function Macros
#define sz(x) ((int)((x).size()))
#define all(x) (x).begin(), (x).end()
#define rep(i, a, b) for (__typeof(a) i = a; i < b; i++)
#define reprev(i, a, b) for (__typeof(a) i = a; i > b; i--)
#define repi(a, b) rep(i, a, b)
#define repj(a, b) rep(j, a, b)
#define repk(a, b) rep(k, a, b)
#define Cmplt(type) bool operator<(const type &o) const
#define Cmpgt(type) bool operator>(const type &o) const
#define Cmpfn(name, type) bool name(const type &a, const type &b)
#define Inop(type) istream& operator>>(istream& in, type &o)
#define Outop(type) ostream& operator<<(ostream& out, type o)
#define Pow2(x) (1LL << (x))
#define scn(type, ...) type __VA_ARGS__; scan(__VA_ARGS__) // scn -> Short for SCan New
// Shorthand Functions
template<typename T> inline void maxa(T& st, T v) { st = max(st, v); }
template<typename T> inline void mina(T& st, T v) { st = min(st, v); }
inline void setprec(ostream& out, int prec) { out << setprecision(prec) << fixed; }
// Out operators and printing for arrays and vectors
template <typename T> ostream& operator<<(ostream& out,vector<T> iter){out<<"[";for(auto t:iter){out<<t<<", ";}out<<"]";return out;}
template <typename T> string arrayStr(T *arr,int sz){string ret = "[";for(int i=0;i<sz;i++){ret+=to_string(arr[i])+", "; } return ret + "]";}
template <typename T> void printArray(T *arr,int sz){for(int i=0;i<sz;i++){cout<<arr[i]<<" "; } cout<<"\n";}
// I/O Operations
inline void scan(){}
template<typename F, typename... R> inline void scan(F &f,R&... r){cin>>f;scan(r...);}
template <typename F> inline void println(F t){cout<<t<<'\n';}
template<typename F, typename... R> inline void println(F f,R... r){cout<<f<<" ";println(r...);}
inline void print(){}
template<typename F, typename... R> inline void print(F f,R... r){cout<<f;print(r...);}
// Debugging
#define db(x) cout << (#x) << ": " << x << ", "
#define dblb(s) cout << "[" << s << "] "
#define dbbin(x, n) cout << (#x) << ": " << bitset<n>(x) << ", "
#define dbarr(x, n) cout << (#x) << ": " << arrayStr((x), (n)) << ", "
#define dbln cout << endl;
#pragma endregion

const int MN = 1e6 + 1;
int n, k, len;
string s;
bool up[MN];

// ds
pii seg[MN << 2];
int lazy[MN << 3], initPfx[MN];
set<int> uppers;

// pair<int, int> -> (val, index)
inline void updLazy(int i) {
    if (lazy[i]) {
        seg[i].first += lazy[i];
        lazy[i << 1] += lazy[i];
        lazy[i << 1 | 1] += lazy[i];
        lazy[i] = 0;
    }
}

pii build(int i, int l, int r){
    if(l == r) return seg[i] = {initPfx[l + len - 1] - initPfx[l - 1], l};
    int mid = (l + r) >> 1;
    return seg[i] = max(build(i << 1, l, mid), build(i << 1 | 1, mid + 1, r));
}

pii update(int i, int bl, int br, int ql, int qr){
    updLazy(i);
    if(qr < bl || ql > br) return seg[i];
    if(bl >= ql && br <= qr) {
        lazy[i]--;
        updLazy(i);
        return seg[i];
    }
    int mid = (bl + br) >> 1;
    return seg[i] = max(update(i << 1, bl, mid, ql, qr), update(i << 1 | 1, mid + 1, br, ql, qr));
    // db(i); db(bl); db(br); db(ql); db(qr); db(seg[i].first); db(seg[i].second); dbln;
    // return seg[i];
}

int solve() {
    // reset ds
    repi(1, n + 1)
        initPfx[i] = initPfx[i - 1] + up[i];

    uppers.clear();
    repi(1, n + 1)
        if (up[i])
            uppers.insert(i);

#define ALL 1, 1, sz
    int sz = n - len + 1;
    build(1, 1, sz);
    memset(lazy, 0, sizeof lazy);

    // start doin shit
    repi(0, k) {
        if (uppers.empty()) break;

        updLazy(1);
        int mx = seg[1].second;

        // db(i); dbln;
        // for (auto x : uppers)
        //     db(x);
        // dbln;
        // db(mx); dbln;

        auto ptr = uppers.lower_bound(mx), ptr2 = uppers.upper_bound(mx + len - 1);
        for (auto it = ptr; it != ptr2; it++) {
            int l = max(1, *it - len + 1), r = min(*it, sz);
            if (l <= r)
                update(ALL, l, r);
            // dblb("rem"); db(*it); dbln;
        }
        uppers.erase(ptr, ptr2);
    }

    return uppers.size();
#undef ALL
}

int main(){
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    scan(n, k, len, s);

    repi(1, n + 1)
        up[i] = isupper(s[i - 1]) != 0;

    // n = 1000000;
    // k = 1000000;
    // len = 1;
    // repi(1, n + 1)
    //     up[i] = i & 1;

    // do and flip
    int best = solve();
    repi(1, n + 1)
        up[i] ^= 1;
    // dblb("tolow"); db(best); dbln;
    // dblb("-------------------------"); dbln;
    mina(best, solve());
    println(best);

    return 0;
}


#pragma region
#include <bits/stdc++.h>
using namespace std;
// Common Type shorteners and int128
using ll = long long; using ull = unsigned long long; using ld = long double;
using pii = pair<int, int>; using pll = pair<ll, ll>;
template <typename T> using vec = vector<T>;
template <typename K, typename V> using umap = unordered_map<K, V>; template <typename K> using uset = unordered_set<K>;
using vi = vec<int>; using vl = vec<ll>; using vpi = vec<pii>; using vpl = vec<pll>;
#ifdef __SIZEOF_INT128__
using int128 = __int128_t; using uint128 = __uint128_t;
#endif
template<typename I> string intStr(I x) { string ret; while (x > 0) { ret += (x % 10) + '0'; x /= 10; } reverse(ret.begin(), ret.end()); return ret; } // Int to string
// Shorthand Macros
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f3f
#define mpr make_pair
#define pb push_back
#define popcount __builtin_popcount
#define clz __builtin_clz
#define ctz __builtin_ctz
// Shorthand Function Macros
#define sz(x) ((int)((x).size()))
#define all(x) (x).begin(), (x).end()
#define rep(i, a, b) for (__typeof(a) i = a; i < b; i++)
#define reprev(i, a, b) for (__typeof(a) i = a; i > b; i--)
#define repi(a, b) rep(i, a, b)
#define repj(a, b) rep(j, a, b)
#define repk(a, b) rep(k, a, b)
#define Cmplt(type) bool operator<(const type &o) const
#define Cmpgt(type) bool operator>(const type &o) const
#define Cmpfn(name, type) bool name(const type &a, const type &b)
#define Inop(type) istream& operator>>(istream& in, type &o)
#define Outop(type) ostream& operator<<(ostream& out, type o)
#define Pow2(x) (1LL << (x))
#define scn(type, ...) type __VA_ARGS__; scan(__VA_ARGS__) // scn -> Short for SCan New
// Shorthand Functions
template<typename T> inline void maxa(T& st, T v) { st = max(st, v); }
template<typename T> inline void mina(T& st, T v) { st = min(st, v); }
inline void setprec(ostream& out, int prec) { out << setprecision(prec) << fixed; }
// Out operators and printing for arrays and vectors
template <typename T> ostream& operator<<(ostream& out,vector<T> iter){out<<"[";for(auto t:iter){out<<t<<", ";}out<<"]";return out;}
template <typename T> string arrayStr(T *arr,int sz){string ret = "[";for(int i=0;i<sz;i++){ret+=to_string(arr[i])+", "; } return ret + "]";}
template <typename T> void printArray(T *arr,int sz){for(int i=0;i<sz;i++){cout<<arr[i]<<" "; } cout<<"\n";}
// I/O Operations
inline void scan(){}
template<typename F, typename... R> inline void scan(F &f,R&... r){cin>>f;scan(r...);}
template <typename F> inline void println(F t){cout<<t<<'\n';}
template<typename F, typename... R> inline void println(F f,R... r){cout<<f<<" ";println(r...);}
inline void print(){}
template<typename F, typename... R> inline void print(F f,R... r){cout<<f;print(r...);}
// Debugging
#define db(x) cout << (#x) << ": " << x << ", "
#define dblb(s) cout << "[" << s << "] "
#define dbbin(x, n) cout << (#x) << ": " << bitset<n>(x) << ", "
#define dbarr(x, n) cout << (#x) << ": " << arrayStr((x), (n)) << ", "
#define dbln cout << endl;
#pragma endregion

const int MN = 1e6 + 1;
int n, k, len;
string s;
bool up[MN];

// ds
pii seg[MN << 2];
int lazy[MN << 3], initPfx[MN];
set<int> uppers;

// pair<int, int> -> (val, index)
inline void updLazy(int i) {
    if (lazy[i]) {
        seg[i].first += lazy[i];
        lazy[i << 1] += lazy[i];
        lazy[i << 1 | 1] += lazy[i];
        lazy[i] = 0;
    }
}

pii build(int i, int l, int r){
    if(l == r) return seg[i] = {initPfx[l + len - 1] - initPfx[l - 1], l};
    int mid = (l + r) >> 1;
    return seg[i] = max(build(i << 1, l, mid), build(i << 1 | 1, mid + 1, r));
}

pii query(int i, int bl, int br, int ql, int qr){
    updLazy(i);
    if(br < ql || bl > qr) return {-INF, -1};
    if(bl >= ql && br <= qr) return seg[i];

    int mid = (bl + br) >> 1;
    return max(query(i << 1, bl, mid, ql, qr), query(i << 1 | 1, mid + 1, br, ql, qr));
}

pii update(int i, int bl, int br, int ql, int qr){
    updLazy(i);
    if(qr < bl || ql > br) return seg[i];
    if(bl >= ql && br <= qr) {
        lazy[i] = -1;
        updLazy(i);
        return seg[i];
    }
    int mid = (bl + br) >> 1;
    return seg[i] = max(update(i << 1, bl, mid, ql, qr), update(i << 1 | 1, mid + 1, br, ql, qr));
    // db(i); db(bl); db(br); db(ql); db(qr); db(seg[i].first); db(seg[i].second); dbln;
    // return seg[i];
}

int solve() {
    // reset ds
    repi(1, n + 1)
        initPfx[i] = initPfx[i - 1] + up[i];

    uppers.clear();
    repi(1, n + 1)
        if (up[i])
            uppers.insert(i);

#define ALL 1, 1, sz
    int sz = n - len + 1;
    build(1, 1, sz);
    memset(lazy, 0, sizeof lazy);

    // start doin shit
    repi(0, k) {
        if (uppers.empty()) break;

        int mx = query(ALL, 1, sz).second;

        // db(i); dbln;
        // for (auto x : uppers)
        //     db(x);
        // dbln;
        // db(mx); dbln;

        auto ptr = uppers.lower_bound(mx), ptr2 = uppers.upper_bound(mx + len - 1);
        for (auto it = ptr; it != ptr2; it++) {
            int l = max(1, *it - len + 1), r = min(*it, sz);
            if (l <= r)
                update(ALL, l, r);
            // dblb("rem"); db(*it); dbln;
        }
        uppers.erase(ptr, ptr2);
    }

    return uppers.size();
#undef ALL
}

int main(){
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    scan(n, k, len, s);

    repi(1, n + 1)
        up[i] = isupper(s[i - 1]);

    // n = 1000000;
    // k = 1000000;
    // len = 1;
    // repi(1, n + 1)
    //     up[i] = i & 1;

    // do and flip
    int best = solve();
    repi(1, n + 1)
        up[i] ^= 1;
    // dblb("tolow"); db(best); dbln;
    // dblb("-------------------------"); dbln;
    mina(best, solve());
    println(best);

    return 0;
}