WQS二分
问题中最多能选择K次,而每次多一次选择得到的价值都小于等于之前的,也就是说
,画出的图像为上凸包:
虽然操作越多越优秀,但是每次增加的量在减少。想想,某个时候会变得很小。
如果我们对这个增加的量减去一个数C,那么某个时候开始就会变小了。
我们想要的是选择次数尽可能小,选的答案尽可能大。
如果我们二分这个C,每次得出:某个合适的时候,选得最大值,以及得到这个最大值的最小次数。
要求次数尽可能小,所以C要尽可能大。
所以最大值为: 二分最大的C,作为每次选择的花费(减在答案值上),然后求出最大的答案值,取此时的次数查看是否符合要求(小于等于K)
如果题目为每次选都减少一部分: 二分最小的C,作为每次选择的花费(加在答案值上),然后求出最小的答案值,取此时的次数查看是否符合要求(小于等于K)
F. New Year and Handle Change
http://codeforces.com/contest/1279/problem/F
题意: 给出一个01串,可以最多选择k个l长度的子串,全部变为0或1。求最后的
解析:
显然的越取加的越少,然后取得次数有上限,很wqs。
代码:
/*
* Author : Jk_Chen
* Date : 2020-01-09-12.07.56
*/
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define rep(i,a,b) for(int i=(int)(a);i<=(int)(b);i++)
#define per(i,a,b) for(int i=(int)(a);i>=(int)(b);i--)
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define fi first
#define se second
#define debug(x) cerr<<#x<<" = "<<x<<'\n'
const LL mod=998244353;
const int maxn=1e6+9;
const int inf=0x3f3f3f3f;
LL rd(){ LL ans=0; char last=' ',ch=getchar();
while(!(ch>='0' && ch<='9'))last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}
#define rd rd()
/*_________________________________________________________begin*/
int n,k,l;
char x[maxn];
LL ans;
#define pill pair<LL, int>
pill dp[maxn];
pill check(LL C){
dp[0]={0,0};
rep(i,1,n){
dp[i]=dp[i-1];
dp[i].first+=x[i];
if(i<=l)dp[i]=min(dp[i],{C,1});
else dp[i]=min(dp[i],{dp[i-l].first+C,dp[i-l].second+1});
}
return dp[n];
}
LL ANS=2e18;
void deal(){
LL l=0,r=n,ans;
while(l<=r){
LL mid=l+r>>1;
if(check(mid).second<=k)ans=mid,r=mid-1;
else l=mid+1;
}
pill res=check(ans);
ANS=min(ANS,res.first-ans*k);//is k not res.second
}
int main(){
n=rd,k=rd,l=rd;
scanf("%s",x+1);
rep(i,1,n){
if(islower(x[i]))x[i]=0;
else x[i]=1;
}
deal();
rep(i,1,n)x[i]=1-x[i];
deal();
printf("%lld\n",ANS);
}