BZOJ1122: [POI2008]账本BBB

版权声明:...............转载说一声并注明出处qaq............... https://blog.csdn.net/L_0_Forever_LF/article/details/78748223

每次取反序列的和改变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;
}
展开阅读全文

没有更多推荐了,返回首页