洛谷1月月赛
A.「EZEC-5」魔法(签到题)
题意:(自己看)
思路:要使区间和最大,显然是先操作加法,然后操作乘法,且每次操作肯定直接操作整个区间即可。直接暴力枚举乘法次数,log的复杂度,然后加法满足二分又一个log的复杂度,check用求最大子段和O(n)
复杂度为
n
l
o
g
2
n
nlog^2 n
nlog2n
小结:有两种操作方法时,可以枚举一个,另一个二分枚举,求满足题意的最值
一个没用的 小知识: 两个long long相乘时,可用__int128 定义他们
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int maxn=1e5+5;
ll n,a,b,s,dp[maxn],p[maxn],ans=inf ,base[maxn];
bool check(int tot1,int tot2){
__int128 sum=0,ma=0; //用__int128 因为可能两个ll相乘
for(int j=1;j<=n;j++){
sum+=p[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("%lld%lld%lld%lld",&n,&a,&b,&s);
for(int i=1;i<=n;i++)
scanf("%lld",&p[i]);
ll mb=log2(s)+1;
for(ll i=0;i<=mb;i++){
ll l=0,r=2e9,now=-1;
while(l<=r){
int mid=(l+r)>>1;
if(check(i,mid)){
now=mid,r=mid-1;
}
else l=mid+1;
}
if(now!=-1)
ans=min(ans,now*a+i*b);
}
printf("%lld\n",ans);
}