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;
}
不摆烂了,写题