题目描述:
你将要实现一个功能强大的整数序列编辑器。在开始时,序列是空的。编辑器共有五种指令,如下:
1、“I x”,在光标处插入数值x。
2、“D”,将光标前面的第一个元素删除,如果前面没有元素,则忽略此操作。
3、“L”,将光标向左移动,跳过一个元素,如果左边没有元素,则忽略此操作。
4、“R”,将光标向右移动,跳过一个元素,如果右边没有元素,则忽略次操作。
5、“Q k”,假设此刻光标之前的序列为a1,a2,…,an,输出max1≤i≤kSi,其中Si=a1+a2+…+ai。
输入格式
第一行包含一个整数Q,表示指令的总数。
接下来Q行,每行一个指令,具体指令格式如题目描述。
输出格式
每一个“Q k”指令,输出一个整数作为结果,每个结果占一行。
数据范围
1≤Q≤10^6,
|x|≤10^3,
1≤k≤n
输入样例:
8
I 2
I -1
I 1
Q 3
L
D
R
Q 2
输出样例:
2
3
样例解释
下图包含了对样例的过程描述:
分析:
题目描述的五种指令分别代表:I-插入元素,D-删除元素,L-删除元素并保存,R-将保存的元素按后出先进的规则再插入,Q-查询前缀和中最大值。
由于有先进后出的性质,考虑采用栈来存储。维护两个栈s,t。I和D分别对应栈s的入栈和出栈操作。L表示将s的栈顶元素弹出保存进t,R代表将t的栈顶元素(若存在)重新压进s栈。至于Q则需要维护一个前缀和数组和一个dp数组,dp[i]表示前i个元素前缀和最大的值,所以Q k操作等价于输出dp[k]。
值得注意的是,仅需要在入栈时更新sum和dp数组,出栈时无需修改,因为下一次入栈会自动更新上次遗留下来没有处理的sum和dp的末尾几个元素。另外,Q的最大值是一百万,使用cin读入数据会超时,加上ios::sync_with_stdio(false);语句便可ac了。
#include <iostream>
#include <algorithm>
#include <stack>
using namespace std;
const int maxn = 1000005;
stack<int> s,t;
long long sum[maxn],dp[maxn];
int p = 0;
void I(int x){
s.push(x);
p++;
sum[p] = sum[p - 1] + x;//更新前缀和
dp[p] = max(dp[p - 1],sum[p]);//更新dp
}
void D(){
if(s.size()){
s.pop();
p--;
}
}
void L(){
if(s.size()){
int x = s.top();
D();
t.push(x);
}
}
void R(){
if(t.size()){
I(t.top());
t.pop();
}
}
void Q(int k){
cout<<dp[k]<<endl;
}
int main(){
ios::sync_with_stdio(false);
sum[0] = 0;
dp[0] = -3000;
int T,x;
char c;
cin>>T;
while(T--){
cin>>c;
if(c == 'I'){
cin>>x;
I(x);
}
else if(c == 'D') D();
else if(c == 'L') L();
else if(c == 'R') R();
else if(c == 'Q'){
cin>>x;
Q(x);
}
}
return 0;
}