Codeforces - New Year and Handle Change

题目链接:Codeforces - New Year and Handle Change


直接dp的话,复杂度是n*k的。

但是我们可以发现,如果我们给每次选择,一个负的代价,那么整体的最优解是一个凸包。我们就可以wqs二分了。

但是要注意,因为选择的次数是小于等于k,但是最优解一定是选k次。因为我们每次转移是从 i - l 转移的,所以如果 i < l 我们也需要转移。


AC代码:

#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include
#define int long long
using namespace std;
const int N=1e6+10;
int n,k,l,a[N],sum[N],dp[N],f[N]; char str[N];
inline int check(int mid){
	for(int i=1;i<=n;i++){
		dp[i]=dp[i-1],f[i]=f[i-1];
		if(i>=l&&dp[i]<dp[i-l]+sum[i]-sum[i-l]-mid) 
			dp[i]=dp[i-l]+sum[i]-sum[i-l]-mid,f[i]=f[i-l]+1;
		else if(i<l&&dp[i]<sum[i]-mid) dp[i]=sum[i]-mid,f[i]=1;
	}
	return f[n];
}
inline int calc(int flag){
	for(int i=1;i<=n;i++) a[i]=flag^(str[i]>='A'&&str[i]<='Z');
	int l=0,r=n,res=0,ans;
	for(int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i]; res+=sum[n];
	while(l<=r){
		int mid=l+r>>1;
		if(check(mid)<=k) ans=mid,r=mid-1;
		else l=mid+1;
	}
	check(ans);
	return res-dp[n]-k*ans;
}
signed main(){
	cin>>n>>k>>l; scanf("%s",str+1);
	cout<<min(calc(1),calc(0));
	return 0;
}

你可能感兴趣的:(Codeforces,动态规划,WQS二分)