2022.4.10#久別了
阿新 • • 發佈:2022-04-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 }