bzoj 1122 [POI2008]账本BBB 模拟贪心,单调队列

 [POI2008]账本BBB

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 524  Solved: 251
[Submit][Status][Discuss]

Description

一个长度为n的记账单,+表示存¥1,-表示取¥1。现在发现记账单有问题。一开始本来已经存了¥p,并且知道最后账户上还有¥q。你要把记账单修改正确,使得 1:账户永远不会出现负数; 2:最后账户上还有¥q。你有2种操作: 1:对某一位取反,耗时x; 2:把最后一位移到第一位,耗时y。

Input

The first line contains 5 integers n, p, q, x and y (1  n  1000000, 0  p;q  1000000, 1  x;y  1000), separated by single spaces and denoting respectively: the number of transactions done by Byteasar, initial and final account balance and the number of seconds needed to perform a single turn (change of sign) and move of transaction to the beginning. The second line contains a sequence of n signs (each a plus or a minus), with no spaces in-between. 1 ≤ n ≤ 1000000, 0 ≤ p ,q ≤ 1000000, 1 ≤x,y ≤ 1000)

Output

修改消耗的时间

Sample Input

9 2 3 2 1
---++++++

Sample Output

3

HINT

若p+序列和≠q,可以发现取反操作数量是确定的
尽量在前面做加法,后面做减法

旋转操作,暴力想法是把最后一位提前,就相当于连成一个环,在环上求值

所以在环上枚举起点

暴力走一遍环单纯是为了解决非负的问题

在环上用单调队列求一遍最小值,再枚举起点做无旋转的修改

 

 1 #include<cstring>
 2 #include<algorithm>
 3 #include<iostream>
 4 #include<cstdio>
 5 #include<queue>
 6 
 7 #define N 1000007
 8 #define ll long long
 9 inline ll read()
10 {
11     ll x=0,f=1;char ch=getchar();
12     while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
13     while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
14     return x*f;
15 }
16 
17 ll n,p,q,x,y;
18 int que[N<<1],seq[N<<1],mn[N];
19 char ch[N];
20 
21 inline ll max(ll a,ll b)
22 {
23     if (a>b) return a;
24     else return b;
25 }
26 inline ll min(ll a,ll b)
27 {
28     if (a>b) return b;
29     else return a;
30 }
31 inline ll abs(ll a)
32 {
33     if (a>0) return a;
34     else return -a;
35 }
36 int main()
37 {
38     n=read(),p=read(),q=read(),x=read(),y=read();
39     scanf("%s",ch+1);
40     for (int i=n<<1;i>n;i--)
41         seq[i]=seq[i+1]+(ch[i-n]=='+'?1:-1);
42     for (int i=n;i>=1;i--)
43         seq[i]=seq[i+1]+(ch[i]=='+'?1:-1);
44     int hd=1,tl=0;
45     for (int i=n<<1;i>=1;i--)
46     {
47         while(hd<=tl&&seq[i]>seq[que[tl]]) tl--;
48         que[++tl]=i;
49         while(hd<=tl&&seq[hd]-i>=n) hd++;
50         if (i<=n) mn[i]=seq[i]-seq[que[hd]];
51     } 
52     ll total=seq[n+1],tmp=(q-p-total)/2,ans=1e16,res;
53     for (int i=0;i<n;i++)
54     {
55         res=x*abs(tmp)+y*(ll)i;
56         if (i==0)
57         {
58             mn[1]+=p+max(tmp,0)*2;
59             if (mn[1]<0) res+=2*x*((1-mn[1])/2);
60         }
61         else
62         {
63             mn[n-i+1]+=p+max(tmp,0)*2;
64             if (mn[n-i+1]<0) res+=2*x*((1-mn[n-i+1])/2);
65         }
66         ans=min(ans,res);
67     }
68     printf("%lld\n",ans);
69 }

 

posted @ 2018-04-14 19:55  Kaiser-  阅读(421)  评论(0编辑  收藏  举报