8-8 Ddfense Line uva1471 优先级队列

  题意:给你一串长度为n的序列   你的任务是删除一个连续的子序列  使得剩下的序列中有一个长度最大的连续递增子序列  例如  将 5 3 4 9 2 8 6 7 1 中的9 2 8 删除  得到5 3 4 6 7 1 中包含一个长度为四的连续子序列

紫书的分析十分好   从n3 到n2 到nlongn 非常精妙   此题细节很多  非常值得学习!!!  注意优先队列的写法。

#include<bits/stdc++.h>
using namespace std;
#define N 200000+5
int a[N];
int n;
int g[N];// g[i] is the length of longest increasing continuous subsequence ending at i
int f[N];

struct node
{
    int a,g;
    node(int a,int g):a(a),g(g){}
    bool operator< (const node &h)const{
      return a<h.a;
    }
};

set<node> s;

int main()
{
    int cas;cin>>cas;
    while(cas--)
    {
        cin>>n;
      for(int i=0;i<n;i++)scanf("%d",&a[i]);

      g[0]=1;
      for(int i=1;i<n;i++)
      if(a[i]>a[i-1])g[i]=g[i-1]+1;
      else   g[i]=1;

     f[n-1]=1;
     for(int i=n-2;i>=0;i--)
        if(a[i]<a[i+1])f[i]=f[i+1]+1;
        else   f[i]=1;

        s.clear();
        s.insert(node(a[0],g[0]));
        int ans=1;
        for(int i=1;i<n;i++)
        {
            node c(a[i],g[i]);
            set<node>::iterator it=s.lower_bound(c);// first one that is >= c
            bool keep=true;
            if(it!=s.begin())
            {
                node last=*(--it);//points to the largest one that is < c
                int len=f[i]+last.g;
                ans=max(ans,len);
                if(c.g<=last.g)keep=false;
            }
            
            if(keep)
            {
                s.insert(c);
                it=s.find(c);// this is a bit cumbersome and slow but it's clear
                it++;
                while(it!=s.end()&&it->a >c.a&&it->g<=c.g)s.erase(it++);
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/bxd123/p/10437688.html