zoukankan      html  css  js  c++  java
  • BZOJ 2457

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2457

    Description
    Sherry现在碰到了一个棘手的问题,有N个整数需要排序。
    Sherry手头能用的工具就是若干个双端队列。
    她需要依次处理这N个数,对于每个数,Sherry能做以下两件事:
    1.新建一个双端队列,并将当前数作为这个队列中的唯一的数;
    2.将当前数放入已有的队列的头之前或者尾之后。
    对所有的数处理完成之后,Sherry将这些队列排序后就可以得到一个非降的序列。

    Input
    第一行包含一个整数N,表示整数的个数。接下来的N行每行包含一个整数Di,其中Di表示所需处理的整数。

    Output
    其中只包含一行,为Sherry最少需要的双端队列数。

    Sample Input

    6

    3

    6

    0

    9

    6

    3

    Sample Output

    2

    HINT
    100%的数据中N≤200000。

    题解:

    假设原序列 $D$ 排序后的序列为 $E$。换句话说,我们就是要将 $E$ 分成若干段,每一段对应原来的一个双端队列。

    现在考虑如何切割 $E$,假设现在我们分割出了其中某一段 $S_1 sim S_n$,那么其中必然有一个数 $S_k(1 le k le n)$ 是第一个进入队列的。

    那么 $S_1 sim S_{k-1}$ 这些数在 $D$ 中的出现顺序必须是降序的。换句话说,在 $S_1 sim S_{k-1}$ 中,$S_1$ 必须是最后一个在 $D$ 中出现的。这是很显然的,它作为最小的,显然必须最后一个push进双端队列的队首。

    同样的道理,$S_{k+1} sim S_n$ 这些数在 $D$ 中的出现顺序必须是升序的。$S_n$ 它作为最大的一个,必须最后一个push进双端队列的队尾。

    也就是说,在 $E$ 中尽可能少地分割出若干段,每段都满足其内部的数在 $D$ 中的出现顺序是先降后升的。这个可以用贪心策略求最少段数。

    另外要考虑的一个问题是,同一个数可能在 $D$ 中不同位置出现,那么我们应当让他们在 $E$ 中有一个合适的顺序,使得分割产生的段数尽量少。这个可以做个分类讨论。

    AC代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef pair<int,int> pii;
    const int maxn=2e5+10;
    
    int n;
    pii a[maxn];
    
    int tot;
    pii bnd[maxn];
    
    int main()
    {
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i].first;
            a[i].second=i;
        }
        sort(a+1,a+n+1);
    
        tot=0;
        for(int i=1;i<=n;i++)
        {
            //printf("val=%d pos=%d
    ",a[i].first,a[i].second);
            if(i==1 || a[i].first!=a[i-1].first)
            {
                bnd[tot].second=a[i-1].second;
                bnd[++tot].first=a[i].second;
            }
        }
        bnd[tot].second=a[n].second;
        //for(int i=1;i<=tot;i++) printf("[%d,%d]
    ",bnd[i].first,bnd[i].second);
    
        int ans=0, pre=maxn, up=1;
        for(int i=1;i<=tot;i++)
        {
            if(up)
            {
                if(pre<bnd[i].first) pre=bnd[i].second;
                else pre=bnd[i].first, up=0, ans++;
            }
            else
            {
                if(pre>bnd[i].second) pre=bnd[i].first;
                else pre=bnd[i].second, up=1;
            }
        }
        cout<<ans<<endl;
    }
  • 相关阅读:
    MySQL update && select ,update的同时select,和for update 语句说再见。
    宋体文件C#读取CSV文件java教程
    输入格式邮箱验证格式
    状态集合[Python]Socket高级 select I/O复用模型(二)
    运行下载运行google play闪退的解决办法java教程
    Hibernate查询
    Hibernare 的基本介绍
    Hibernate详细配置
    人工智能能力提升指导总结
    如何根据普通ip地址获取当前地理位置
  • 原文地址:https://www.cnblogs.com/dilthey/p/9919479.html
Copyright © 2011-2022 走看看