正解:离散化+二分答案
错解:离散化+dp (也许能做吧大概因为我太弱了TT
解题报告:
最初看到这题是hl大佬想做这题然后去看题解没看懂离散化……然后我就去看了下 因为我tql就看懂了这个很妙的东西 那时候大概就似懂非懂的感觉趴,第一次正式接触离散化,之前听到过很多次这个概念但真正知道这个神仙玩意儿大概就是在那个时候……但是其实那个时候我并没有完全懂这个神仙东西吧,然后也没有去做所以其实并乜有落实这个玩意儿。然后之后又做了几个离散化的题目之后才真正明白这个神仙东西……不过不得不说这个题目的题解真滴讲得挺好的算是个炒鸡好的启蒙辣
dbq又跑题了要被hl大佬骂说浪费时间了QAQ
然后今天突然被另一个大佬问到了这题所以就尝试了下
因为现在对离散化还是有点儿了解了嘛,就信心满满地跑上去做了
然后就T了5个点……
来我直接放错误代码然后再分析错哪儿了QAQ
#include<bits/stdc++.h> using namespace std; #define ll long long ll ys[100010],a[100010],f[100010],maxans; ll read() { char ch=getchar();ll x=0; while(ch<'0' || ch>'9')ch=getchar(); while(ch>='0' && ch<='9')x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return x; } int main() { ll n=read(); for(ll i=1;i<=n;i++)ys[read()]=i; for(ll i=1;i<=n;i++){a[i]=ys[read()];for(ll j=i-1;j>=1;j--)if(a[j]<a[i])f[i]=max(f[i],f[j]+1);} for(ll i=1;i<=n;i++)maxans=max(maxans,f[i]+1); cout<<maxans; return 0; }
然后你就会发现!!!这个的复杂度是n2啊!!!怎么可能不T!不T都没有天理了484!!!所以这里用dp显然是沙雕行为只有我这种弱鸡才会犯这种蠢问题TT
那正解究竟是什么呢……我点开了题目标签,居然看到一个,二分答案???什么玩意儿这个用二分答案???
然后我想了半天实在想不出来,就又去看题解……发现我其实不会求最长上升序列……dp不是最优解……
好那我接下来就港下nlogn的二分正解
先介绍个神奇的东西,叫 lower_bound() 这是个,好东西,相当于是个二分的思想,找在一个有序序列中最小的比我要找的数大的数的位置是哪个,但是是用的STL实现的,就很简单嘛
介绍下这个想法的原理,就是从前往后找,存到f序列中的一个过程,f是个存最长上升序列的玩意儿
那么有两种情况
如果目前扫到的数比f中max还大 就把它放到f的最后就成了
如果小呢?那f中比它大的数中最小的那个数就是没有意义的了,我们可以把这个数用我们目前扫到的数替换掉,这样一路扫下去,最后输出f中有几个数就成了!
这样的话我们就是nlogn的复杂的了(扫一遍n,找logn
好那讲清楚了吧我觉得?就直接放代码!
#include<bits/stdc++.h> using namespace std; #define ll long long ll ys[100010],f[100010],ans; ll read() { char ch=getchar();ll x=0; while(ch<'0' || ch>'9')ch=getchar(); while(ch>='0' && ch<='9')x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return x; } int main() { ll n=read(); for(ll i=1;i<=n;i++)ys[read()]=i; for(ll i=1;i<=n;i++) { ll t=read(); if(ys[t]>f[ans])f[++ans]=ys[t]; else f[lower_bound(f+1,f+ans+1,ys[t])-f]=ys[t]; } cout<<ans; return 0; }
完美结束!yeah!
然后为了实现第二种情况,我们可以强行让f是有序序列,然后用lower_bound找f序列中最小的那个比它大的数就欧克了