WQS二分(F. New Year and Handle Change)

WQS二分

问题中最多能选择K次,而每次多一次选择得到的价值都小于等于之前的,也就是说 F ( x + 1 ) x + 1 F ( x ) x \frac{F(x+1)}{x+1}\leq\frac{F(x)}{x} ,画出的图像为上凸包:
在这里插入图片描述

虽然操作越多越优秀,但是每次增加的量在减少。想想,某个时候会变得很小。

如果我们对这个增加的量减去一个数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。求最后的 m i n ( s i z e    0 , s i z e    1 ) min(size \;0,size\;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);
}

发布了723 篇原创文章 · 获赞 314 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/103936234