「EZEC-5」魔法

在这里插入图片描述
输入:
5 2 3 102
-3 -1 1 -2 0

输出:
17
在这里插入图片描述
思路: 核心:枚举优化+二分
对于区间加法操作,肯定是将整个区间+1最划算;
对于区间乘法操作,肯定是将最大区间乘2最划算。
对于加法和乘法混用,先做加法再做乘法最划算。
观察数据范围 s ≤ 1e9,2的31次方左右差不多,所以枚举乘法次数,再二分加法次数,即可求最小花费。

//二分
//先加再乘
//枚举乘,然后加法二分
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef long long ll;
ll n,a,b;
ll s;
const int N=1e5+10;
ll dp[N];
ll arr[N];
ll qsm(ll a , ll b)
{
    
    
    ll ans=1,temp=a;
    while( b )
    {
    
    
        if( b & 1)  ans = (ans * temp );
        temp *= temp;
        b >>= 1;
    }
    return ans;
}
bool check( ll y ,ll x)
{
    
    
    ll maxn=-1e18;
    ll sum=0;
    //求最大字段和
    for( int i=1 ;i<=n ;i++)
    {
    
    
        if( sum < 0) sum=0;
        sum += arr[i] + y;
        maxn = max ( maxn, sum);
    }
    if( maxn<=0 )   return false;
    //写成1.0 * s qsm(2,x)会爆longlong,
	return maxn >=1.0 * s / qsm(2,x );
}
ll cal(int x)
{
    
    
    ll l = 0 , r = 3*1e9+10;
    while( l <= r )
    {
    
    
        ll mid = ( l+r )>>1;
        if( check(mid,x) )  r = mid-1;
        else l = mid+1;
    }
    return x * b + l * a;
}
signed main()
{
    
    
//    ios::sync_with_stdio(false);
//    cin.tie(0);cout.tie(0);
    cin>>n>>a>>b>>s;
    for(int i=1 ;i<=n ;i++)
        cin>>arr[i];
    ll res=1e18;
    //因为乘法最多32次,枚举乘法,二分加法即可
     for(int i=0 ;i<=32 ;i++)
     {
    
    
         res = min( res ,cal(i));
     }
     cout<<res<<endl;
}

猜你喜欢

转载自blog.csdn.net/m0_53688600/article/details/114966169