題意:一個長爲n的字符串,含有大寫字母或小寫字母,最多進行k次操作,將長爲l範圍內的字符全部變爲小寫或全部變爲大寫,求min(lower,upper)的最小值,其中lower是小寫字母的數量,upper是大寫字母的數量.n,k,l<=1e6,l<=n
二分+動態規劃.
首先二分枚舉每次操作最少使lower(upper)數量減少y,然後dp轉移,只有在lower(upper)的數量大於等於y時才發生轉移,dp值表示在最少減少y之外額外減少的lower(或upper)的值,最後需要使得操作次數<=k;經過二分得到最小的k值,此時減少後lower的數量即爲答案.
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long long LL;
typedef long double lb;
#define ri register int
const lb PI=3.141592653589793238462643383279;
const ll inf=1000000000000000000ll;
const int N=1000005,M=998244353;
int n,i,k,p,j,l,r,ans;
int s[N],t[N];
long long dp[N];
char c[N];
int check(int y,bool type,bool f)
{
int i;
for(i=1;i<=n;++i)
{
if(c[i]>='A'&&c[i]<='Z')
s[i]=type;
else
s[i]=type^1;
s[i]+=s[i-1];
}
cout<<y<<endl;
for(i=1;i<=n;++i)
{
dp[i]=max(dp[i-1],(i-p<0?0:dp[i-p]-s[i-p])+s[i]-y);
if(dp[i-1]>(i-p<0?0:dp[i-p]-s[i-p])+s[i]-y)
t[i]=t[i-1];
else
if(dp[i-1]<(i-p<0?0:dp[i-p]-s[i-p])+s[i]-y)
t[i]=t[i-p]+1;
else
t[i]=min(t[i-1],t[i-p]+1);
// cout<<dp[i]<<" "<<t[i]<<endl;
}
if(f)
{
ans=min(1ll*ans,s[n]-dp[n]-k*y);
}
return t[n];
}
int main()
{
scanf("%d %d %d",&n,&k,&p);
scanf("%s",c+1);
l=0,r=p;
ans=n;
while(l<r)
{
int mid=l+r>>1;
if(check(mid,0,0)<=k)
r=mid;
else
l=mid+1;
}
check(l,0,1);
l=0,r=p;
while(l<r)
{
int mid=l+r>>1;
if(check(mid,1,0)<=k)
r=mid;
else
l=mid+1;
}
check(l,1,1);
cout<<ans;
}