6

【题解】P7287魔法

 3 years ago
source link: https://blog-e.tk/2021/01/25/%E9%A2%98%E8%A7%A3-P7287%E9%AD%94%E6%B3%95/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
【题解】P7287魔法 - Blog E

题目在此:P7287

  1. 所有的 1 操作一定在所有的 2 操作之前进行
  2. 每个 1 操作的范围一定是 [1,n]
  3. 每次 2 操作都是对当前序列的最大字段和那个区间进行的。
  4. 最终选的区间是最终序列的最大子段和

1,2,4 都很显然,3 结论可感性理解(这个野鸡博主不会证):

如果每次都选那个最大子段和进行操作,那得到的结果一定是最优的。 否则一旦在操作过程中有操作的区间不是最大子段和区间的话,在进行同样次操作之后的结果是不优的。

现在,我们只需要知道 1 操作以及 2 操作的次数,就能算出最终数列的最大最大字段和。接着观察发现2操作的次数是不超过log(值域)次的。

所以我们只需枚举 2 操作的次数,再二分出 1 操作的次数即可。

#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define rd scanf
#define pt printf
#define setp(x) setprecision(x)
#define mem(x,y) memset(x,y,sizeof(x))
#define sz(x) (int)x.size()
#define umn(x,y) x=min(x,y)
#define umx(x,y) x=max(x,y)
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll,ll> pi;
typedef vector<ll> vi;
typedef vector<pi> vpi;

const double eps=1e-9;
const ll INF=1e18;
const ll P=998244353;
const ll MXN=1e5+5;

inline ll mod(ll x){return x>=P?x-P:x;}
inline ll mul(ll x,ll y){if(x<y)swap(x,y);ll res=0;while(y){if(y&1)res=mod(res+x);x=mod(x<<1);y>>=1;}return res;}
inline ll qpow(ll x,ll y){ll res=1;while(y){if(y&1)res=res*x%P;x=x*x%P;y>>=1;}return res;}
ll gcd(ll x,ll y){return !y?x:gcd(y,x%y);}
inline void pbin(ll x,ll y){for(;~y;y--)cerr<<char('0'+((x>>y)&1));cerr<<endl;}



ll n,a,b,s;
ll arr[MXN];
inline ll cal(ll add){
	ll last=0,ans=0;
	for(int i=1;i<=n;i++){
		last=max(last,0ll)+arr[i]+add;
		umx(ans,last);
	}
	return ans;
}
inline bool chk(ll add,ll pwr){
	ll tmp=cal(add);
	for(int i=0;i<=pwr;i++)
		if((tmp<<i)>=s)return 1;
	return 0;
}


inline void solve(){
    //codes
	cin>>n>>a>>b>>s;
	for(int i=1;i<=n;i++)cin>>arr[i];

	ll ans=INF;
	for(int i=0;i<=32;i++){
		ll l=0,r=2e9;
		while(l<r){
			ll mid=(l+r)>>1;
			if(chk(mid,i))r=mid;
			else l=mid+1;
		}
		ans=min(ans,a*l+b*i);
	}
	cout<<ans;
    
}
int main(){
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	ios_base::sync_with_stdio(0);cin.tie(0);
	cout<<setiosflags(ios::fixed);
	srand(time(NULL));

	solve();
	return 0;
}

作者:@ethan-enhe
本文为作者原创,转载请注明出处:本文链接

阅读量 63


来发评论吧~
Powered By Valine
v1.4.4

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK