4 条题解

  • 0
    @ 2024-11-24 12:19:48

    钱的2分法,待看:

    #include<bits/stdc++.h>
    using namespace std;
    int n;
    int cnt;
    int main(){
    	cin>>n;
    	vector<int> dp(n+1,INT_MAX);
    	int len=1;
    	dp[0]=0;
    	for(int i=0;i<n;i++){
    		cin>>cnt;
    		//					//O(log(dp.size()))
    		int it=upper_bound(dp.begin(),dp.end(),cnt)-dp.begin();
    		if(it>len){
    			dp[++len]=cnt;
    		}
    		else{
    			dp[it]=cnt;
    		}
    		for(int j=1;j<len+1;j++){
    			cout<<dp[j]<<' ';
    		}
    		cout<<endl;
    	}
    	cout<<len;
    	return 0;
    }
    
    
    • 0
      @ 2024-8-31 1:59:36

      二分普通方法:

      #include <bits/stdc++.h>
      using namespace std;
      int main() {
          int n;
          cin >> n;
          vector<int> a(n);
          for (int i = 0; i < n; i++) {
              cin >> a[i];
          }
          vector<int> dp;        // 存储当前 LIS 的最小末尾元素
          vector<int> pos(n, -1);  // 记录 dp 中的每个位置的索引
          vector<int> prev(n, -1); // 记录每个元素的前驱索引
          for (int i = 0; i < n; i++) {
              // 使用二分查找找第一个大于等于 a[i] 的位置
              auto it = lower_bound(dp.begin(), dp.end(), a[i]);
              int idx = it - dp.begin();
              if (it == dp.end()) {
                  dp.push_back(a[i]);  // 如果没有找到位置,说明 a[i] 可以作为 LIS 的新元素
              } else {
                  *it = a[i];  // 替换掉 dp 中的元素
              }
              pos[idx] = i; // 记录在 dp 中每个位置对应的原始数组索引
              if (idx > 0) {
                  prev[i] = pos[idx - 1]; // 记录当前元素的前驱索引
              }
          }
          // 通过前驱索引回溯构造 LIS
          vector<int> lis;
          for (int i = pos[dp.size() - 1]; i != -1; i = prev[i]) {
              lis.push_back(a[i]);
          }
          reverse(lis.begin(), lis.end());
          cout << "Max=" << dp.size() << endl;
          for (int num : lis) {
              cout << num << " ";
          }
          cout << endl;
          return 0;
      }
      
      
      • 0
        @ 2024-8-31 1:57:09

        二分查找DP字典序最小:

        #include <bits/stdc++.h>
        using namespace std;
        int main() {
            int n;
            cin >> n;
            vector<int> a(n);
            for (int i = 0; i < n; i++) {
                cin >> a[i];
            }
            vector<int> dp;          // 存储当前 LIS 的最小末尾元素
            vector<int> pos(n, -1);  // 记录 dp 中的每个位置的索引
            vector<int> prev(n, -1); // 记录每个元素的前驱索引
            vector<int> indices(n);  // 记录当前的元素在原数组中的位置
            for (int i = 0; i < n; i++) {
                auto it = lower_bound(dp.begin(), dp.end(), a[i]);
                int idx = it - dp.begin();
                if (it == dp.end()) {
                    dp.push_back(a[i]);
                    if (!dp.empty()) {
                        prev[i] = pos[idx - 1]; // 前驱索引
                    }
                } else {
                    *it = a[i];
                    if (idx > 0) {
                        prev[i] = pos[idx - 1];
                    }
                }
                pos[idx] = i;
            }
            // 回溯以构造 LIS,确保字典序最小
            vector<int> lis;
            for (int i = pos[dp.size() - 1]; i != -1; i = prev[i]) {
                lis.push_back(a[i]);
            }
            reverse(lis.begin(), lis.end());
            cout << "Max=" << dp.size() << endl;
            for (int num : lis) {
                cout << num << " ";
            }
            cout << endl;
            return 0;
        }
        
        
        • 0
          @ 2024-8-31 1:35:02

          从前往后代码:

          #include <bits/stdc++.h>
          using namespace std;
          int main() {
              int n;
              cin >> n; 
              vector<int> a(n);         // 存储输入数组
              vector<int> dp(n, 1);     // dp[i] 存储以 a[i] 结尾的最长不下降子序列的长度
              vector<int> prev(n, -1);  // prev[i] 存储构造最长子序列时 a[i] 的前一个元素的索引
              int maxcnt = 0;           // 存储最长不下降子序列的长度
              int maxIndex = 0;         // 存储最长不下降子序列最后一个元素的索引
              for(int i = 0; i < n; i++)  cin >> a[i];
              for(int i = 1; i < n; i++) {
                  for(int j = 0; j < i; j++) {  // 这里 j 从 0 开始遍历到 i-1
                      if(a[i] >= a[j] && dp[i] < dp[j] + 1) { // 更新条件:a[i] >= a[j]
                          dp[i] = dp[j] + 1;
                          prev[i] = j;  // 更新前驱索引
                      }
                  }
                  if(dp[i] > maxcnt) {  // 找到当前最大长度和对应的索引
                      maxcnt = dp[i];
                      maxIndex = i;
                  }
              }
              cout << "Max=" << maxcnt << endl;
              // 回溯构造最长不下降子序列
              vector<int> lis;
              for(int i = maxIndex; i != -1; i = prev[i]) {
                  lis.push_back(a[i]);
              }
              reverse(lis.begin(), lis.end());
          	int len=lis.size();
              for(int i = 0; i < len; i++) {
                  cout << lis[i] << " ";
              }
              cout << endl;
              return 0;
          }
          
          
          • 1

          信息

          ID
          737
          时间
          1000ms
          内存
          256MiB
          难度
          7
          标签
          递交数
          44
          已通过
          11
          上传者