【bzoj5427】最长上升子序列(贪心+LIS)

  题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=5427

  因为noip,博客咕了好久,这几天集中填一下坑。

  这题我们可以假设往不确定的空位里填数,然后考虑一下如何尽可能让空位多被选上。我们发现,如果有一个空位没在最后的最长上升子序列里,那么可以贪心地去掉一个被选上的数再加上去。

  那么我们假定所有的空位都被选上。这样原序列就被划分成了许多段,而每一段内的在最长上升子序列里的数都必须与两边相差至少2(留一个数给空位)。那么我们可以把每一段数整体减去前面空位的数量(即每个数的数值减去前面没被确定的数的个数),然后直接跑一遍最长上升子序列,加上空位数量就行了。

  代码:

#include<cstdio>
#include<set>
using namespace std;
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read(){int tmp=0; char c=nc(),f=1; for(;c<'0'||'9'<c;c=nc())if(c=='-')f=-1; for(;'0'<=c&&c<='9';c=nc())tmp=(tmp<<3)+(tmp<<1)+c-'0'; return tmp*f;}
set<int>st;
int n,k,delta=0;
int main()
{
    n=read();
    for(int i=1;i<=n;i++){
        char ch=nc();
        while(ch<'A'||'Z'<ch)ch=nc();
        if(ch=='K'){
            k=read();
            set<int>::iterator iter=st.lower_bound(k-delta);
            if(iter==st.end())st.insert(k-delta);
            else if(*iter+delta>k)st.erase(iter),st.insert(k-delta);
        }
        else{
            ++delta;
            st.insert(-1000000000-delta);
        }
    }
    printf("%d
",st.size());
}
bzoj5427
原文地址:https://www.cnblogs.com/quzhizhou/p/10070606.html