2022.4.10#久别了
一段时间埋头做题,感觉还是应当要记录的。
2022-04-10
这两天,lis问题和树链剖分
lis有两种,O(n^2),O(nlogn)都是用dp做,第一种可以记录序列,第二种只有长度
第一种思想是,对于每一个元素,dp记录它的最长长度,通过和之前的进行一一比较,dp[i]=dp[j]+1
输出的思想是,利用链式前向星的想法,从后往前记录,给个head记录最长序列的尾元素
1 //输出序列的O(n^2),思想是dp记录每个字母的最长 2 //我利用链式先向星的思想,为最长的那个非递增序列记录下来 3 #include<iostream> 4 #include<algorithm> 5 #include<cstdlib> 6 #include<vector> 7 using namespace std; 8 #define maxn 100010 9 int dp[maxn]; 10 int nxt[maxn]; 11 int maxsize; 12 int head; 13 vector<int> vec; 14 int main(void) 15 { 16 for(int i=0;i<maxn;i++) 17 nxt[i]=-1; 18 while(1) 19 { 20 int temp; 21 scanf("%d",&temp); 22 vec.push_back(temp); 23 char ch; 24 ch=getchar(); 25 if(ch!=' ') 26 break; 27 } 28 29 30 for(int i=maxn-1;i>=0;i--) 31 { 32 dp[i]=1; 33 } 34 35 head=0;//最长非递增序列的最后一个元素下标 36 for(int i=0;i<vec.size();i++) 37 { 38 for(int j=0;j<i;j++) 39 { 40 if(vec[j]>=vec[i]) 41 { 42 if(dp[j]+1>dp[i]) 43 { 44 dp[i]=dp[j]+1; 45 nxt[i]=j;//利用链式前向星的思想从后往前 46 if(dp[i]>maxsize) 47 { 48 maxsize=dp[i]; 49 head=i; 50 } 51 } 52 } 53 } 54 } 55 cout<<dp[vec.size()-1]<<endl; 56 vector<int>res; 57 for(int i=head;i>=0;i=nxt[i]) 58 { 59 res.push_back(vec[i]); 60 } 61 for(int i=res.size()-1;i>=0;i--) 62 cout<<res[i]<<" "; 63 return 0; 64 }
第二种相对方便,dp记录的是每一个长度的最后元素,有种顶堆的感觉,然后每次进行比对即可
值得一提的是它的优化在于dp数组中,以及是有序的排列了,因为如果不有序是不可能形成你要的序列,所以对于有序的序列我们可以使用二分查找,故降低时间复杂度
这里提供upper_bound,lower_bound
1 #include<iostream> 2 #include<algorithm> 3 using namespace std; 4 int main(void) 5 { 6 int a[]={389,207,155}; 7 int b[]={155,207,389}; 8 int index=upper_bound(a,a+3,389,greater<int>())-a;//第一个小于389的 9 int index2=lower_bound(a,a+3,389,greater<int>())-a;//第一个小于等于389的 10 int index3=upper_bound(b,b+3,389)-b;//第一个大于389的 11 int index4=lower_bound(b,b+3,389)-b;//第一个大于等于389的 12 cout<<index<<endl; 13 cout<<index2<<endl; 14 cout<<index3<<endl<<index4<<endl; 15 return 0; 16 }
然后是代码
1 #include<iostream> 2 #include<algorithm> 3 #include<vector> 4 using namespace std; 5 #define maxn 100010 6 int dp[maxn]; 7 vector<int> vec; 8 int main(void) 9 { 10 while(1) 11 { 12 int temp; 13 scanf("%d",&temp); 14 vec.push_back(temp); 15 char ch; 16 ch=getchar(); 17 if(ch!=' ') 18 break; 19 } 20 int cnt=0; 21 for(int i=0;i<vec.size();i++) 22 { 23 if(cnt==0) 24 dp[++cnt]=vec[i]; 25 else 26 { 27 if(dp[cnt]>=vec[i]) 28 dp[++cnt]=vec[i]; 29 else 30 { 31 *upper_bound(dp+1,dp+1+cnt,vec[i],greater<int>())=vec[i]; 32 } 33 } 34 } 35 cout<<cnt<<endl; 36 cnt=0; 37 memset(dp,0,sizeof(dp)); 38 for(int i=0;i<vec.size();i++) 39 { 40 if(cnt==0) 41 dp[++cnt]=vec[i]; 42 else 43 { 44 if(dp[cnt]<vec[i]) 45 dp[++cnt]=vec[i]; 46 else 47 { 48 *lower_bound(dp+1,dp+1+cnt,vec[i])=vec[i]; 49 } 50 } 51 } 52 cout<<cnt<<endl; 53 return 0; 54 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通