HDU 4699(栈)

题意

现在要求模拟一个文档编辑,有5种操作,I x:在光标后面插入一个数字x,且光标后以一位,相当于输入;D:删除光标前面的一个数字,相当于backpack;L:将光标向左移动一位;R:光标向右移动一位;Q x:查询前x个数字的最大前缀和,保证x在光标位置之前。

分析

由于每次操作都是在光标所在的位置,而且只改变一位。所以我们可以用光标模拟栈顶指针,将光标左边的数字,也就是有效数字存进一个栈中。对于I操作,相当于将x压入栈,对于D操作相当于pop栈顶元素。最后的查询是要求最大的前缀和,而且他保证了查询的位置一定是在光标前,所以我们可以对光标前的数字,也就是栈中的数字建立前缀数组sum,并且用另一个数组dp记录从开始到当前位置中的最大前缀和,那么对于Q操作直接输出dp[x]即可。

还有剩下两个操作,左移和右移。因为左移以后的数字并不是被删除了,当右移的时候还需要重新利用,这个时候我们模拟下可以发现,右移的这个操作可以看成是另一个栈,每当右移的时候将原来栈顶的元素放在另一个栈中,然后左移的时候将另个栈的栈顶元素重新压回来。

最后说下sum数组和dp数组是如何建立的,因为要存的是栈中的数字,所以每当有入栈操作的时候就要计算前缀和以及更新dp数组。也就是I操作和R操作。

代码中还要注意一点的是,如果当前光标已经是第一个了,那么再往左边移动也是不变的,也就相当于,第一个栈的元素如果是空的话,是无法出栈的。同理当光标是最后一个位置的时候右移也是无法移动的,这相当于第二个栈如果是空的话,也是无法出栈的。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
const int MAXN = 1e6;
ll sum[MAXN + 5], dp[MAXN + 5];
int main()
{
    ios::sync_with_stdio(false);
    int n;
    while (cin >> n)
    {
        memset(sum, 0, sizeof(sum));
        memset(dp, 0, sizeof(dp));
        dp[0] = -10000000000000000;

        string op;
        int x;
        stack<int> a, b;

        while (n--)
        {
            cin >> op;
            if (op[0] == 'I')
            {
                cin >> x;
                a.push(x);
                int pos = a.size();
                sum[pos] = sum[pos - 1] + x;
                dp[pos] = max(dp[pos - 1], sum[pos]);
            }
            else if (op[0] == 'D')
            {
                a.pop();
            }
            else if (op[0] == 'L')
            {
                if (a.size()) 
                {
                    x = a.top();
                    a.pop();
                    b.push(x);
                }
            }
            else if (op[0] == 'R')
            {
                if (b.size())
                {
                    x = b.top();
                    b.pop();
                    a.push(x);
                    int pos = a.size();
                    sum[pos] = sum[pos - 1] + x;
                    dp[pos] = max(dp[pos - 1], sum[pos]);
                }
            }
            else
            {
                cin >> x;
                cout << dp[x] << endl;
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值