输入:
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;
}