bzoj 1122 [POI2008]账本BBB 模拟贪心,单调队列
[POI2008]账本BBB
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 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 }