一道杨氏矩阵的题,萌新初入门,还不是很懂, 讲的超级好(就是看图有点麻烦)
据说这玩意儿可以代替堆和平衡树用,支持插入、删除、查询,跑得还挺快的(慢着,复杂度好像是 n^2 ? 而且空间要求爆炸!)
emmm 总之就是跑不满的吧,反正做这道题 n^2 也是正解了啊...
我们考虑杨氏矩阵是一个满足任意元素的右方和下方相邻元素都比该元素小(或大)的矩阵,空着的元素可以默认为 inf
这个性质有点像堆...不过正是这个性质使得杨氏矩阵可以解决一些特殊的问题,比如这道题
我们考虑单单去求一个最长不降子序列的长度,那么最快办法就是去二分优化 dp 转移了
这里的杨氏矩阵的做法极其类似,不信的话你甚至可以把第一行的最终元素输出来看看,和自己打的最长不降子序列比对一下,你就会发现两者相同...
//by Judge#include#include #define Rg register#define fp(i,a,b) for(Rg int i=(a),I=(b)+1;i I;--i)using namespace std;const int M=5005;#ifndef Judge#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)#endifchar buf[1<<21],*p1=buf,*p2=buf;inline bool cmin(int& a,int b){return a>b?a=b,1:0;}inline int read(){ int x=0,f=1; char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f;} char sr[1<<21],z[20];int CCF=-1,Z;inline void Ot(){fwrite(sr,1,CCF+1,stdout),CCF=-1;}inline void print(int x,char chr='\n'){ if(CCF>1<<20)Ot();if(x<0)sr[++CCF]=45,x=-x; while(z[++Z]=x%10+48,x/=10); while(sr[++CCF]=z[Z],--Z);sr[++CCF]=chr;} int n,x,ans;struct Matrix{ int a[M][M]; int* operator [](const int& x){return a[x];} inline void insert(Rg int x,Rg int y,Rg int v){ cmin(y,*a[x]); while(y&&a[x][y]>v) --y; ++y; if(y>*a[x]) a[x][++*a[x]]=v; else insert(x+1,y,a[x][y]),a[x][y]=v; }}p;int main(){ n=read(); fp(i,1,n) x=read(),p.insert(1,n,x); fp(i,1,n) if(!p[i][0]) break; else print(ans+=p[i][0]); return Ot(),0;}