每次取反序列的和改变2,旋转和不变
根据原始序列的和,q-p可以算出至少要取反的次数,如果额外的次数记作花费,产生花费只可能是因为某个前缀和<0
预处理1~i,i~n前缀和的最小值,因为至多旋转n-1次,枚举旋转次数,算粗前缀和最小的位置,保证这个位置>=0就可以保证序列合法,算一下花费什么的
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
inline void read(int &x)
{
char c; while(!((c=getchar())>='0'&&c<='9'));
x=c-'0';
while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
}
const int maxn = 1100000;
int n,p,q,x,y;
char str[maxn];
int sum[maxn],pre[maxn],suf[maxn];
ll re,ans;
int main()
{
scanf("%d%d%d%d%d",&n,&p,&q,&x,&y);
scanf("%s",str+1); sum[0]=p;
for(int i=1;i<=n;i++)
sum[i]=sum[i-1]+(str[i]=='+'?1:-1);
suf[n+1]=suf[n]=sum[n]; pre[1]=sum[1];
for(int i=2;i<=n;i++) pre[i]=min(pre[i-1],sum[i]);
for(int i=n-1;i>=1;i--) suf[i]=min(sum[i],suf[i+1]);
re=LLONG_MAX;
for(int i=2;i<=n+1;i++)
{
ll temp=(ll)(n-i+1)*y;
int mn=min(suf[i]-sum[i-1],pre[i-1]+sum[n]-sum[i-1]),oth=0;
if(mn<0) oth=(1-mn)/2,temp+=(ll)oth*x;
int tmp=sum[n]+oth*2;
temp+=(ll)abs(q-tmp)/2*x;
re=min(re,temp);
}
printf("%lld\n",re);
return 0;
}