P7287 「EZEC-5」魔法 题解(二分套二分)

题目链接

题目思路

显然是先操作加法,然后操作乘法

且每次操作肯定直接操作整个区间即可,

直接暴力枚举乘法次数,log的复杂度

然后加法满足二分又一个log的复杂度

check用求最大子段和O(n)

复杂度为\(nlog_2^2n\)

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
const ll INF=0x3f3f3f3f3f3f3f3f;
int n,a,b,s;
ll k[maxn];
ll base[maxn];
bool check(int tot1,int tot2){
    __int128 sum=0,ma=0; //用__int128 因为可能两个ll相乘
    for(int j=1;j<=n;j++){
        sum+=k[j]+tot2;
        if(sum<0){
            sum=0;
        }
        ma=max(ma,sum);
    }
    ma=ma*base[tot1];
    return ma>=s;
}
int main(){
    base[0]=1;
    for(int i=1;i<=40;i++){
        base[i]=base[i-1]*2;
    }
    scanf("%d%d%d%d",&n,&a,&b,&s);
    for(int i=1;i<=n;i++){
        scanf("%lld",&k[i]);
    }
    int cnt=log2(s)+1;
    ll pr=INF;
    for(int i=0;i<=cnt;i++){
        ll l=0,r=2e9,ans=-1;
        while(l<=r){
            ll mid=(l+r)>>1;
            if(check(i,mid)){ // mul 2^i, add mid
                ans=mid;
                r=mid-1;
            }else{
                l=mid+1;
            }
        }
        if(ans!=-1){ //满足
            pr=min(pr,1ll*i*b+1ll*ans*a);
        }
    }
    printf("%lld\n",pr);
    return 0;
}

posted @ 2021-01-23 20:33  hunxuewangzi  阅读(152)  评论(0编辑  收藏  举报