整理的算法模板合集: ACM模板
给出一个⻓度为n的数字序列 a i {ai} ai,我们需要找到一个最⻓的子序列, 使得子序列中的数字大小单调递增。 例如: n = 5 n = 5 n=5,原序列为 ( 1 , 4 , 2 , 3 , 5 ) (1,4,2,3,5) (1,4,2,3,5),那么我们选择 ( 1 , 2 , 3 , 5 ) (1,2,3,5) (1,2,3,5)是最优的。
最长上升子序列是不能等于的,后面要大于前面,所以要正序,并且查询的时候要-1来保证只会小于不会等于
最长不上升子序列是可以等于的,其实就是求小于等于,所以后面的要小于等于前面的,由于树状数组维护的是最大值(大于等于),而这里要的是小于等于,所以要倒序。
要注意这里要用maxn也就是a数组里的最大值来作为树状数组的上限
因为树状数组里存的就是a数组的值,并维护其最大值
ll n,m,ans1,ans2,tree[N],a[N],maxn; inline void update(ll k,ll val)//更新 { while(k<=maxn)//要注意这里是maxn也就是a数组里的最大值来作为树状数组的上限 { tree[k]=max(tree[k],val);//维护最大值 k+=k&(-k); } } inline ll query(ll k) { ll res=0; while(k) { res=max(res,tree[k]);//求以小于等于x的数为结尾的最长不上升子序列的长度的最大值 k-=k&(-k); } return res; } int main() { while(scanf("%lld",&a[++n])!=EOF)maxn=max(maxn,a[n]); n--; for(int i=n;i>=1;--i) { ll q=query(a[i])+1; /*相当于朴素做法的:for(int j=i+1;j<=n;j++) if(a[j]<=a[i]) 因为是按照顺序从后往前循环,所以当前的i所query到的所有的值都是在i后面的, 解决了i<j的问题,树状数组维护最大值,就解决了a[j]<=a[i]的问题, 所以这里求的就是以i为开头的最长不上升子序列的长度*/ update(a[i],q);//这个最大值+1就是以当前这个数开头的最长不上升子序列的长度,丢到树状数组里面去更新后面的值 ans1=max(ans1,q); } memset(tree,0,sizeof tree); for(int i=1;i<=n;++i) { ll q=query(a[i]-1)+1; /*查询以小于(没有等于!!!)x的数为结尾的最长上升子序列的长度的最大值 因为不能等于所以要-1*/ update(a[i],q);//这个最大值+1就是以当前这个数结尾的最长上升子序列的长度,丢到树状数组里面去 ans2=max(ans2,q); } printf("%lld\n%lld\n",ans1,ans2); return 0; }给出两个⻓度为n的序列 { a i } 和 { b i } \{a_i\}和\{b_i\} {ai}和{bi},求它们的公共子序列的最⻓⻓ 度。 例如两个序列分别为 ( 1 , 2 , 4 , 8 , 16 ) (1,2,4,8,16) (1,2,4,8,16)和 ( 2 , 4 , 6 , 8 , 10 ) (2,4,6,8,10) (2,4,6,8,10),那么它们的 L C S LCS LCS就是 ( 2 , 4 , 8 ) (2,4,8) (2,4,8)。