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 }
复制代码

 

posted @   Tiachi  阅读(34)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示