bzoj1122: [POI2008]账本BBB
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
题解:
http://blog.csdn.net/wzq_qwq/article/details/48528159
code:
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 using namespace std; 7 char ch; 8 bool ok; 9 void read(int &x){ 10 for (ok=0,ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1; 11 for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar()); 12 if (ok) x=-x; 13 } 14 const int maxn=2000005; 15 typedef long long int64; 16 char s[maxn]; 17 int n,p,q,x,y,sum[maxn],minv[maxn],tmp,head,tail; 18 int64 ans=1LL<<60; 19 struct Data{ 20 int val,id; 21 }que[maxn]; 22 int main(){ 23 read(n),read(p),read(q),read(x),read(y); 24 scanf("%s",s+1); 25 for (int i=n<<1;i>n;i--) sum[i]=sum[i+1]+(s[i-n]=='+'?1:-1); 26 for (int i=n;i;i--) sum[i]=sum[i+1]+(s[i]=='+'?1:-1); 27 head=1,tail=0; 28 for (int i=n<<1;i;i--){ 29 while (head<=tail&&que[head].id>i+n) head++; 30 while (head<=tail&&que[tail].val<sum[i]) tail--; 31 que[++tail]=(Data){sum[i],i}; 32 minv[i]=sum[i]-que[head].val; 33 } 34 tmp=(q-p-sum[n+1])>>1; 35 for (int i=1;i<=n;i++){ 36 int64 res=1LL*(n-i+1)%n*y+abs(tmp)*x; 37 minv[i]+=p+max(tmp,0)*2; 38 if (minv[i]<0) res+=((1-minv[i])>>1)*x*2; 39 ans=min(ans,res); 40 } 41 printf("%lld\n",ans); 42 return 0; 43 }