luogu P7287 「EZEC-5」魔法

题面传送门
挺好的一道题。
首先一个很明显的贪心:先加后乘,这样一定最大。
然后又注意到,在最大子段和为正时,第二个操作的使用次数不会超过\(logs\)次。
所以可以枚举第二个操作的执行次数。
那么第一个操作显然是在刚好的时候最优,这个用二分可以轻松解决。
时间复杂度\(O(nlog^2s)\)
代码实现:

#include<cstdio>
#define ll long long
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
int n,m,k,x,y,z;
long long s,a[100039],b[100039],ans=1e18,now=1,pus,tot,l,r,mid;
inline int check(long long mid){
	register int i;
	for(i=1;i<=n;i++) a[i]+=mid;
	tot=pus=0;
	for(i=1;i<=n;i++){
		tot+=a[i];
		if(tot<0)tot=0;
		pus=max(pus,tot);
	}
	for(i=1;i<=n;i++) a[i]-=mid;
	return pus?((s+pus-1)/pus<=now):0;
}
int main(){
	freopen("1.in","r",stdin);
	register int i,j;
	scanf("%d%d%d%lld",&n,&m,&k,&s);
	for(i=1;i<=n;i++) scanf("%lld",&a[i]);
	for(i=0;i<=35;i++){
		l=-1;r=2e9;
		while(l+1<r){
			mid=l+r>>1;
			if(check(mid)) r=mid;
			else l=mid;
		}
		ans=min(ans,(ll)i*k+(ll)r*m);
		now<<=1;
	}
	printf("%lld\n",ans);
}
上一篇:luogu P7597 「EZEC-8」猜树 加强版


下一篇:BZOJ 2818 欧拉函数,线性筛