HDU 4604 Deque(LIS 转化)

解决序列与双向队列问题的高效算法
本文探讨了一种解决序列与双向队列问题的高效算法,通过分析序列和队列的特性,提出了利用单增序列和单减序列合成来最大化队列长度的方法。此外,文章还讨论了元素重复情况下的优化策略,并提供了一个实现该算法的代码片段。重点在于优化算法性能,以应对大规模数据处理的需求。

题目链接:Click here~~

题意:

给一个序列 {An} 和一个双向队列 D,每次可以向 D 的队首或队尾插入一个元素,且 D 要保证单调不减,问如何使最后队列的长度最长。

解题思路:

先考虑单调递增的情况,对于 D 所能够构成的每一种序列,都可以看做以某个元素 Ax 为起始元素所形成的单增序列 Px 和单减序列 Qx 合成的。

由于除了 Ax, Px 和 Qx 不会有其他交集,所以一定有 max( |D| ) <= max( |Px| ) + max( |Qx| )  - 1。

所以,只要对于每个Ax,都能快速得到它相应的 max( |Px| ) 和 max( |Qx| ),问题就可以解决了。

回顾求单调最长序列的过程,我们每次更新的时候,其实都是相当于把 Ai 插到了以 Ai 为末尾元素能够构成的最长单调序列的长度那里。

然后,我们求最长序列时从 n~1 逆向循环,就可以“负负得正”,将末尾元素变成起始元素了。

此题还需要考虑元素相同的情况,于是我们插入 Ai 时,判断 Ai 是否和长度比它少 1 的末尾元素相等,如果相等,则 cnt[Ai]++。

最后总序列中 Ax 的个数,应该等于 max( cnt(Ax) ∈ Px , cnt(Ax) ∈ Qx )。

小技巧:求单调递减序列比较麻烦(重载cmp函数 || 不能用pair),所以可以将元素全取相反数,然后继续求递增。

目前代码有bug。慎入。

#include <stdio.h>
#include <string.h>
#include <algorithm>

using namespace std;

const int N = 1e5 + 5;

pair<int,int> dp1[N],dp2[N];

int a[N],top1,top2;

int main()
{
    int T,n;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        dp1[top1=1] = make_pair(a[n],1);
        dp2[top2=1] = make_pair(-a[n],1);
        int ans = 1;
        for(int i=n-1;i>=1;i--)
        {
            int j1 = upper_bound(dp1+1,dp1+1+top1,make_pair(a[i],N)) - dp1;
            if(j1 == top1 + 1)
                top1++;
            int cnt1 = a[i] == dp1[j1-1].first ? dp1[j1-1].second + 1 : 1;
            dp1[j1] = make_pair(a[i],cnt1);

            int j2 = upper_bound(dp2+1,dp2+1+top2,make_pair(-a[i],N)) - dp2;
            if(j2 == top2 + 1)
                top2++;
            int cnt2 = -a[i] == dp2[j2-1].first ? dp2[j2-1].second + 1 : 1;
            dp2[j2] = make_pair(-a[i],cnt2);

            ans = max(ans,j1+j2-min(cnt1,cnt2));
        }
        printf("%d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值