[bzoj1122][貪心][亂搞]賬本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
題解
挺不錯的一道題
先考慮沒有2操作的情況
暫時不考慮 的關係
這樣的話只需要讓 最小即可
顯然是把-1變成1,一次貢獻是2,只需要變 次
變完之後顯然
再考慮 與 的關係
-1變1顯然在儘量靠前的位置
1變-1顯然在儘量靠後的位置
小於的時候是把-1變1對 沒有影響可以直接做了
大於的時候其實也沒有影響…這個想一想就可以知道的
所以知道 之後 變的次數是固定的
可以
2操作的話,列舉2操作次數,實際上只需要維護一個動態字首和最小值
單調佇列即可
線段樹被卡飛了啊…
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define lc now<<1
#define rc now<<1|1
using namespace std;
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int stack[20];
inline void write(int x)
{
if(!x){putchar('0');return;}
int top=0;
while(x)stack[++top]=x%10,x/=10;
while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);printf(" ");}
inline void pr2(int x){write(x);puts("");}
int mn[2];
int n,S,T,c1,c2;
char ch[1000005];
int a[2000005];
int pre[2000005],li[2000005],head,tail;
int main()
{
// freopen("4.in","r",stdin);
n=read();S=read();T=read();c1=read();c2=read();
//更改 移位
scanf("%s",ch+1);int to=0;
for(int i=1;i<=n;i++)a[i]=a[i+n]=(ch[i]=='-'?-1:1),to+=a[i];
for(int i=1;i<=2*n;i++)pre[i]=pre[i-1]+a[i];
int ggg=0;
int ans;
head=1;tail=0;
for(int i=2*n;i>=n+1;i--)
{
while(head<=tail&&pre[li[tail]]>=pre[i])tail--;
li[++tail]=i;
// modify(1,1,2*n,i,i,ggg+a[i]);
// ggg+=a[i];
}S+=to;
mn[1]=pre[li[head]]-pre[n];
if(S-to+mn[1]>=0)ans=(abs(S-T)+1)/2*c1;
else
{
int cnt=S-to+mn[1];
ans=-(cnt-1)/2*c1;
ans+=(abs(S-((cnt-1)/2*2)-T)+1)/2*c1;
}
for(int i=n;i>1;i--)
{
int sum=(n-i+1)*c2;
while(head<=tail&&li[head]>=i+n)head++;
while(head<=tail&&pre[li[tail]]>=pre[i])tail--;
li[++tail]=i;
mn[1]=pre[li[head]]-pre[i-1];
if(S-to+mn[1]>=0)sum+=(abs(S-T)+1)/2*c1;
else
{
int cnt=S-to+mn[1];
sum+=-(cnt-1)/2*c1;
sum+=(abs(S-((cnt-1)/2*2)-T)+1)/2*c1;
}
ans=min(ans,sum);
}
pr2(ans);
return 0;
}