1. 程式人生 > 其它 >2022.4.10#久別了

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 }