题目
有五种操作
I
I
I
x
:
x:
x:在当前光标处插入一个整数x,插入后光标移动到x之后
D
:
D:
D:删除光标前的一个整数
L
:
L:
L:光标向左移动一个位置
R
:
R:
R:光标向右移动一个位置
Q
Q
Q
x
:
x:
x:在位置
x
x
x之前的最大的前缀和
分析
这样的操作不难想到对顶栈的方法,而栈
A
A
A表示光标处(栈顶)至开头(栈底)的子序列,栈
B
B
B表示光标处至末尾的子序列,
s
u
m
sum
sum表示前缀和,
f
f
f表示最大的前缀和(动态规划)
当操作
I
I
I
x
x
x时
- 把 x x x插入栈 A A A
- s u m [ c u r s o r ] = s u m [ c u r s o r − 1 ] + x sum[cursor]=sum[cursor-1]+x sum[cursor]=sum[cursor−1]+x
- f [ c u r s o r ] = m a x ( f [ c u r s o r − 1 ] , s u m [ c u r s o r ] ) f[cursor]=max(f[cursor-1],sum[cursor]) f[cursor]=max(f[cursor−1],sum[cursor])
当操作
D
D
D时把
A
A
A的栈顶弹出
当操作
L
L
L时把
A
A
A的栈顶插入
B
B
B并弹出
A
A
A的栈顶
当操作
R
R
R时
- 把 B B B的栈顶插入 A A A并弹出 B B B的栈顶
- s u m [ c u r s o r ] = s u m [ c u r s o r − 1 ] + x sum[cursor]=sum[cursor-1]+x sum[cursor]=sum[cursor−1]+x
- f [ c u r s o r ] = m a x ( f [ c u r s o r − 1 ] , s u m [ c u r s o r ] ) f[cursor]=max(f[cursor-1],sum[cursor]) f[cursor]=max(f[cursor−1],sum[cursor])
当操作 Q Q Q x x x时,直接输出 f [ x ] f[x] f[x]
代码
#include <cstdio>
#include <stack>
using namespace std;
stack<int>a; stack<int>b; int n,num,sum[1000001],f[1000001];
int in(){
int ans=0,f=1; char c=getchar();
while ((c<48||c>57)&&c!='-') c=getchar();
if (c=='-') c=getchar(),f=-f;
while (c>47&&c<58) ans=ans*10+c-48,c=getchar();
return ans*f;
}
int main(){
while (scanf("%d",&n)==1){//多组数据
while (a.size()) a.pop();//清空栈
while (b.size()) b.pop();
f[0]=-99999999; sum[0]=0; num=0;//f初始很小的数
while (n--){
char c=getchar();
while (c<65||c>91) c=getchar(); //保险起见
if (c=='I'){//操作I
int x=in();
a.push(x);
sum[++num]=sum[num-1]+a.top();//更新前缀和
f[num]=max(f[num-1],sum[num]);//dp
}
else if (c=='D'){
if (!num) continue;//注意勿越界
num--,a.pop();
}
else if (c=='L') {
if (!num) continue;
num--,b.push(a.top()),a.pop();
}
else if (c=='Q') printf("%d\n",f[in()]);
else{
if (b.empty()) continue;
a.push(b.top()); b.pop();
sum[++num]=sum[num-1]+a.top();
f[num]=max(f[num-1],sum[num]);
}
}
}
return 0;
}