• 3743. 【TJOI2014】Alice and Bob(alice)


    Description

    Alice 和 Bob 发明了一个新的游戏。给定一个序列 \(\{x_0,x_1,…,x_{n-1}\}\)。Alice 得到一个序列 \(\{a_0,a_1,…,a_{n-1}\}\),其中 \(a_i\) 表示以 \(x_i\) 结尾的最长上升子序列的长度;Bob 得到一个序列\(\{b_0,b_1,…,b_{n-1}\}\),其中 \(b_i\) 表示以 \(x_i\) 开头的最长下降子序列的长度。 Alice 的得分是序列 \(\{a_0,a_1,…,a_{n-1}\}\) 的和,Bob 的得分是 \(\{b_0,b_1,…,b_{n-1}\}\) 的和。

    Solution

    由于 \(x\) 中相同的元素没有贡献,因此我们钦定 \(x\)\(1\sim n\) 的排列。

    题目给出了 \(a\) 序列,要最大化 \(b\) 序列。那么我们可以根据 \(a\) 序列来约束 \(x\) 序列,从而得到最大的 \(b\) 序列。

    对于 \(i<j\),如果 \(a_i\ge a_j\),则说明 \(x_i>x_j\),反之则可以将 \(x_j\) 接在 \(x_i\) 后面。

    如果 \(a_i+1=a_j\),则至少有一个 \(i\) 满足 \(x_i<x_j\)

    那我们可以尝试用 \(\mathrm{dfs}\) 来解决这个问题。

    对于每个 \(a_i\),找到最靠近的 \(a_j\) 满足 \(a_j+1=a_i\),连一条 \((i,j)\) 的边。

    注意要使用前向星,因为前向星的特性就是后加入的边先遍历

    然后求出 \(\mathrm{dfs}\) 序,可以证明 \(\mathrm{dfs}\) 序就是 \(x\) 序列。

    求出 \(x\) 序列后,可以用 \(\mathcal O(n\log n)\) 求出 \(b\) 序列。

    Code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 100005
    #define ll long long
    using namespace std;
    struct node
    {
        int to,next;
    }a[N<<1];
    int n,x,tot,cnt,len,t[N],head[N],dfn[N],b[N],c[N];
    ll ans;
    void add(int x,int y)
    {
        a[++tot].to=y;
        a[tot].next=head[x];
        head[x]=tot;
    }
    void dfs(int x,int fa)
    {
        dfn[x]=++cnt;
        for (int i=head[x];i!=-1;i=a[i].next)
        {
            int v=a[i].to;
            if (v==fa) continue;
            dfs(v,x);
        }
    }
    int main()
    {
        freopen("alice.in","r",stdin);
        freopen("alice.out","w",stdout);
        memset(head,-1,sizeof(head));
        scanf("%d",&n);
        for (int i=1;i<=n;++i)
        {
            scanf("%d",&x);
            add(t[x-1],i);add(i,t[x-1]);
            t[x]=i;
        }
        dfs(0,-1);
        for (int i=1;i<=n;++i)
            --dfn[i];
        for (int i=1;i<=n;++i)
            b[i]=dfn[n-i+1];
        len=0;
        for (int i=1;i<=n;++i)
        {
            int l=1,r=len,mid;
            while (l<=r)
            {
                mid=(l+r)>>1;
                if (b[i]>c[mid]) l=mid+1;
                else r=mid-1;
            }
            len=max(len,l);
            c[l]=b[i];
            ans=ans+(ll)l;
        }
        printf("%lld\n",ans);
        return 0;
    }
    
  • 相关阅读:
    BZOJ2762: [JLOI2011]不等式组
    BZOJ1452: [JSOI2009]Count
    Codeforces Round #441 (Div. 2, by Moscow Team Olympiad)
    BZOJ1635: [Usaco2007 Jan]Tallest Cow 最高的牛
    BZOJ2730: [HNOI2012]矿场搭建
    Flask实现异步非阻塞请求功能
    在flask中使用websocket-实时消息推送
    Python数据库连接池DBUtils
    flask请求上下文
    scanf与getchar
  • 原文地址:https://www.cnblogs.com/Livingston/p/15808023.html
Copyright © 2020-2023  润新知