AcWing 128.编辑器
话说这题要拿80还是挺简单的,我居然都可以想到对顶栈的办法。
本题参考动态中位数的对顶堆思想,很容易想到以光标为分界线,将已有的序列划分别划入两个栈中。我们不妨将这种方法命名为“对顶栈”。
前面4个操作的实现相当简单,但是最后一个略显困难。当然,我们很容易想到一种暴力枚举的方法如下:
while(Q--){
char c;
cin>>c;
if(c=='I'){
int x;
cin>>x;
stk2[++top2]=x;
}
if(c=='D'){
if(top2){
top2--;
}
}
if(c=='L'){
if(top2){
stk1[++top1]=stk2[top2];
top2--;
}
}
if(c=='R'){
if(top1){
stk2[++top2]=stk1[top1];
top1--;
}
}
if(c=='Q'){
int x;
cin>>x;
int ans=0,zf=0;
for(int i=1;i<=min(top2,x);i++){
if(stk2[i]>0 || i==1){
if(zf+stk2[i]>0 || i==1){
ans+=zf+stk2[i];
zf=0;
}
else zf+=stk2[i];
}
else{
zf+=stk2[i];
}
}
cout<<ans<<endl;
}
}
这种方法当然不够优秀,只能拿到80pts,所以我们要尝试优化,将所有操作的复杂度提升至O(1)。那么,通过思考可知:新加入一个数以及向右移动光标时需要更新答案。我们不妨用数组f[i]来存储答案,询问时直接输出f[k]即可。而f数组的求法也很简单,见代码。
if(c=='I'){
int x;
scanf("%d",&x);
stk2[++top2]=x;
if(x+sum[top2-1]-f[top2-1]>0 || top2==1){
f[top2]=x+sum[top2-1];
}
else f[top2]=f[top2-1];
sum[top2]=x+sum[top2-1];//sum是前缀和数组
}
if(c=='R'){
//两处代码完全相同
if(top1){
int x=stk1[top1];
stk2[++top2]=x;
top1--;
if(x+sum[top2-1]-f[top2-1]>0 || top2==1){
f[top2]=x+sum[top2-1];
}
else f[top2]=f[top2-1];
sum[top2]=x+sum[top2-1];
}
}
总结:“对顶”数据结构适合维护一个有序的序列,支持删除、加入、在线询问等操作。要视具体情况正确使用不同的结构。
1.AcWing 129.火车进栈
本题数据范围较小,又是要输出方案,必然想到用dfs。那么此处的dfs较为特殊,是每次有两种选择的dfs(每次可以选择将栈顶的数出栈或者是将下一个数进栈),那么代码就应当写成每次递归只进行一次操作的样子,而不是循环多次操作。代码如下:
#include<iostream>
using namespace std;
const int N=25;
int stack[N],cnt,top,ans[N],m;
int n;
void dfs(int x){
if(x==n+1){
cnt++;
if(cnt>20) return;
for(int i=