拦截导弹 题解

拦截导弹

https://ac.nowcoder.com/acm/problem/16810

本题要求的是一个最大不增子序列长度和一个最大递增子序列的长度。
关于这两个问题的求解,过于经典不再赘述。
问题的关键是第二个问题是如何转化而来的。
第二个问题是通过Dilworth定理得到的。
引入两个离散数学的概念:
链(chain)是一个偏序集S的全序子集(所谓全序是指任意两个元素可比较)
反链(antichain)是一个偏序集S的子集,其中任意两个元素不可比较.
dilworth说的是:最大链的长度等于最少反链覆盖数.而最大反链的长度等于最少链覆盖数.

离散数学中有一个知识点叫作二元关系,所谓二元关系通俗的理解就是某一个元素有两个键值,用以下的代码来简单的理解一下

struct node
{
    inta,b;
}
bool operator < (node n1,node n2)
{
    return n1.a<n2.a&&n1.b<n2.b;
}
在以上例子中,只有一个对象的a,b均小于另一个对象,两者才可比。
那么在一个序列中,我们将一个元素的值记作a,所在的位置记作b。
那么当且仅当位置靠左的元素小于位置靠右的元素的时候,这两者才可比。
所以在这里一个最长的链,就是最长递增子序列
同理,当位置靠左的元素不小于位置靠右的元素时,满足n1.b<n2.b但是不满足n1.a<n2.a
两者不可比较,反链要求其中任意两个元素均不可比较,那么最长的反链就是最长不增子序列。
再运用dilworth定理,我们便可以得到,最大不增子序列的覆盖数就等于最长递增子序列的长度

#include <bits/stdc++.h>
using namespace std;
int a[100100];
int L[100100];
int main()
{
    int tmp;
    int n=0;
    while(scanf("%d",&tmp)!=EOF)
    {
        a[++n]=tmp;
    }
    int len=0;
    for(int i=n;i>=1;i--)
    {
        if(len==0)
            L[++len]=a[i];
        else if(a[i]>=L[len])
            L[++len]=a[i];
        else
        {
            int p=upper_bound(L+1,L+1+len,a[i])-L;
            L[p]=a[i];
        }
    }
    printf("%d\n",len);
    len=0;
    memset(L,0,sizeof(L));
    for(int i=1;i<=n;i++)
    {
        if(len==0)
            L[++len]=a[i];
        else if(a[i]>L[len])
            L[++len]=a[i];
        else
        {
            int p=lower_bound(L+1,L+1+len,a[i])-L;
            L[p]=a[i];
        }
    }
    printf("%d\n",len);
}
全部评论

相关推荐

06-13 12:13
已编辑
东北大学 射频工程师
26毕业的,日常实习还能找到吗
求实习的青提很想去大厂:目前应该还有hc吧,腾讯感觉还有hc,最近捞了我好几次,因为目前有offer,所以不准备面了,可以再找找,不行的话就找找中小厂试试,因为我之前也找了好久,准备放弃了,结果有个岗位流程特别顺利,然后就oc,只能说坚持下试试,万一呢💪
点赞 评论 收藏
分享
05-30 18:54
武汉商学院 Java
湫湫湫不会java:先投着吧,大概率找不到实习,没实习的时候再加个项目,然后把个人评价和荣誉奖项删了,赶紧成为八股战神吧,没实习没学历,秋招机会估计不多,把握机会。或者说秋招时间去冲实习,春招冲offer,但是压力会比较大
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务