3 条题解

  • 2
    @ 2026-10-21 10:22:20

    上:B站、抖音

    下:B站、抖音

    • -1
      @ 2026-10-22 20:40:29
      #include<bits/stdc++.h>
      using namespace std;
      int a[1010];
      int dp[1010];
      int wshisgcxdog[1010];
      int main(){
      	int n=1,ans=0;
      	while(cin>>a[n++]);
      	n-=2;wshisgcxdog[1]=a[1];
      	dp[1]=1;
      	for(int i=2;i<=n;i++){
      		dp[i]=1;
      		for(int j=1;j<i;j++){
      			if(a[i]<=a[j]){
      				dp[i]=max(dp[j]+1,dp[i]);
      			} 
      		}
      	}
      	for(int i=1;i<=n;i++){
      		ans=max(dp[i],ans);
      	}
      	cout<<ans<<endl;
      	int xt=1;
      	
      	for(int i=2;i<=n;i++){
      			int t=0;
      			for(int j=1;j<=xt;j++){
      			
      				if(wshisgcxdog[j]>=a[i]){
      					t=1;
      					wshisgcxdog[j]=a[i];
      					break;
      				}
      				
      			}
      			if(t==0){
      				xt++;
      				wshisgcxdog[xt]=a[i];			
      			}	
      		}
      		cout<<xt;	
      	return 0;
      }
      
      
      

      注意数组名字

      • -2
        @ 2026-10-20 20:50:53

        题目简化 给定一个数列 b,问:

        它的最长不上升子序列长度; 最少能被划分成多少个不上升子序列。 思路讲解 一、为什么要求 最长不上升子序列: 但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。

        rt,因为每一个系统的第 i 发高度都不能高于第 i−1 发的高度,则该数列为 不上升子序列。

        二、为什么要求 最长上升子序列: Dilworth 定理 对偏序集 ⟨A,≤⟩,设 A 中最长链的长度是 n,则将 A 中元素分成不相交的反链,反链个数至少是 n。

        名词解释:

        偏序关系:对于集合 A 上的二元关系 R,若 R 具有自反性,反对称性,传递性,那么 R 称为 A 的偏序关系,一般记作 ≤(注意这里的 ≤ 不必是指一般算数意义上的“小于等于”。)。

        偏序集:若在集合 A 上给定一个偏序关系 ≤,则称集合 A 按偏序关系 ≤ 构成一个偏序集合,集合 A 和偏序 R 一起称为偏序集,记作 ⟨A,≤⟩。

        反链:对于偏序集合 ⟨A⟩,在 ⟨A⟩ 的一个子集中,如果每两个元素都是无关的,则称这个子集为反链。

        综上可简化为:最少的不上升子序列的个数就是最长上升子序列的长度。

        偏序集 ⟨A,≤⟩ 是指数列 b。 所以得出结论:导弹系统最少套数就是最长上升子序列的长度。

        代码实现 一、求最长不上升子序列: 用普通的方法是不可以的,那个的时间复杂度是 O(n 2 )。 所以需要用到 stl 函数:lower_bound 与 upper_bound。 对这个不熟悉的同学可以看 oiwiki STL 算法部分。

        变量声明: 数组 b 存储从输入数据; 数组 l 存储最长不上升子序列; 变量 r1 代表 l 的结尾位置(即最长不上升子序列的长度)。

        把 b 中的每个元素挨个放到 l 里:

        如果 b i ​ ≤l r1 ​ ,说明 b i ​ 可以直接加入 l(而整个 l 数组还是有序的);

        如果 b i ​

        l r1 ​ ,说明若放入 b i ​ 则 l 会无序,所以要找办法把 b i ​ 放进去:

        怎么放呢?在 l 中找到第一个小于 b i ​ 的数,用 b i ​ 代替它。 找到第一个小于 b i ​ 的数,使用 upper_bound 可以在 O(logn) 复杂度内找到(需要改比较器)。

        由于它返回的是指针就可以有一些奇特操作。

        *upper_bound(l+1, l+r1+1, b[i], greater()) = b[i];

        证明: 更优性证明:

        设找到的数为 l p ​ 。

        如果 l p ​ 在末尾,由于 l p ​ <b i ​ ,所以 l p ​ 后面能接的没有 b i ​ 多,l p ​ 让位给 b i ​ 可以让序列更长。

        如果 l p ​ 不在末尾,那 l p ​ 以后都不会再被用到了,直接换了 l p ​ 就行。

        有序性证明:

        设 l p ​ 前面是 p 1 ​ ,l p ​ 后面是 p 2 ​ ,则有

        p 1 ​ ≤l p ​ ≤p 2 ​

        因为 l p ​ 是第一个小于 b i ​ 的,所以有

        b i ​ ≤p 2 ​

        又因为

        p 1 ​ ≤l p ​ ≤b i ​

        所以

        p 1 ​ ≤b i ​ ≤p 2 ​

        综上,b i ​ 可以完美代替 l p ​ 。

        实际上,l p ​ 的含义是:最大不上升子序列长度为 p 时,最优的结尾元素。 最后 r1 就是要求的最大不上升子序列长度。

        二、求最长上升子序列长度 这里和上面很像,所以不用改比较器,而且因为是上升序列,所以要用 lower_bound。

        基本上是“同上”二字就可以概括。

        CODE
        
        #include <bits/stdc++.h>
        using namespace std;
        #define ll long long
        const int man = 1e5+10;
        
        int n, r1, r2;
        int a[man], l[man], h[man];
        int main () {
        #ifndef ONLINE_JUDGE 
            freopen("test.in", "r", stdin);
            freopen("test.out", "w", stdout);
        #endif
            while (scanf("%d", a+(++n)) != EOF) ; --n;
            l[1] = h[1] = a[1]; r1 = r2 = 1;
            for(int i = 2; i <= n; ++ i) {
                if (l[r1] >= a[i]) l[++r1] = a[i];
                else *upper_bound(l+1, l+r1+1, a[i], greater<int>()) = a[i];
                if (h[r2] < a[i]) h[++r2] = a[i];
                else *lower_bound(h+1, h+r2+1, a[i]) = a[i];
            } printf("%d\n%d", r1, r2);
            return 0;
        }
        

        扩展:Dilworth 定理的证明 施归纳于 n。

        当 n=1 时: 命题显然成立。

        假设对于 n=k 结论成立,考虑 n=k+1 的情况: 当 A 中最长链的长度为 k+1 时,令 M 为 A 中极大元的集合,显然 M 是一条反链。而且 A−M 中最长链的长度为 k。

        由归纳假设,可以把 A−M 分成至少 k 个不相交的反链,加上反链 M,则 A 可分成至少 k+1 条反链。 因为 A 不可能分解成 n−1 条反链。假若只有 n−1 条反链,那么最长链的 n 个元素中必有 2 个元素被分到同一个反链,显然这与反链的定义矛盾。

        • 1

        信息

        ID
        208
        时间
        1000ms
        内存
        256MiB
        难度
        9
        标签
        (无)
        递交数
        86
        已通过
        9
        上传者