题目
Description
给出N个数,它们各不相同,求最长上升子序列
Input
先给出一个数字N,代表有N组数据
对于每组数据,先给出一个数字TOT,TOT小于等于40000.
接下来有TOT个数字,为1到40000的某个排列.
Output
针对每组数据,输出最长上升序列的长度
Sample Input
4 6 4 2 6 3 1 5 10 2 3 4 5 6 7 8 9 10 1 8
8 7 6 5 4 3 2 1 9 5 8 9 2 3 1 7 4 6
Sample Output
3 9 1 4
思路:
本是一道dp题,但数据给了加强,那么就需要优化;
首先来看看dp的代码:
dp[1]=1; for(ll i=1;i<=n;i++) { ll sum=0; for(ll j=1;j<=i;j++) if(a[j]<a[i]) sum=max(sum,dp[j]); dp[i]=sum+1; } ll ans=0; for(ll i=1;i<=n;i++) ans=max(ans,dp[i]); printf("%lld ",ans);
那么怎么优化呢?-----树状数组
我们看到代码中有两行
for(ll j=1;j<=i;j++) if(a[j]<a[i])
一般有这个代码的dp题目都可以用树状数组来优化;
如果不信的巨佬看看我之前写的树状数组优化题目;
所以
for(ll j=1;j<=i;j++) if(a[j]<a[i]) sum=max(sum,dp[j]);
就可以转化为求1-a[i]的最大值
如下网址:https://www.cnblogs.com/wzx-RS-STHN/p/13193271.html(树状数组中求1-x的最大值);
代码
#include<bits/stdc++.h> typedef long long ll; using namespace std; inline ll read() { ll a=0,f=1; char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();} return a*f; } ll n,mx; ll sum[40001],a[40001]; inline ll lowbit(ll x) { return x&(-x); } inline void insert(ll x,ll y)//加入 { while(x<=mx)//!!! { sum[x]=max(sum[x],y);//cout<<"a"<<x<<" "<<y<<endl;改代码的痕迹 x+=lowbit(x); } } inline ll findout(ll x)//查找 { ll ans=0; while(x) { ans=max(ans,sum[x]);//cout<<"x"<<x<<endl; x-=lowbit(x); } return ans; } int main() { ll o=read(); while(o--) { mx=0; memset(sum,0,sizeof(sum));//清零 memset(a,0,sizeof(a)); n=read(); for(ll i=1;i<=n;i++) a[i]=read(), mx=max(mx,a[i]); insert(a[1],1);//先把第一个加入,因为第一个的dp[1]总是1 ll ans=0; for(ll i=2;i<=n;i++) { // if(a[i]==5) // cout<<sum[4]<<endl改代码的艰难痕迹 ll x=findout(a[i]); ans=max(ans,x+1); // cout<<a[i]<<" "<<x<<endl; insert(a[i],x+1); } printf("%lld ",ans);//就这么多了,没什么讲的 } }