AtCoder Regular Contest 080 E - Young Maids

原创 2018年04月16日 16:37:34

题意

给出一个排列,要求按如下方式构造一个新排列,使得新排列的字典序尽量小。
每次可以在原排列中选择两个相邻的数,将这两个数在原排列中删掉并按照原来的相对顺序放在新排列的最前面。
n<=200000

分析

由于要字典序最小,我们可以倒着贪心。
首先找到下标奇偶性不同且字典序最小的两个数(a[x],a[y]),那么a[x]和a[y]就会作为新排列的开头,然后将序列拆分成三个区间[1,x),(x,y),(y,n]。
按照这个思路,我们可以用一个堆来维护每个区间的字典序,然后每次取字典序最小的区间出来,将该区间的两个元素输出后把其分成三个区间再扔进堆里面即可。
找最小值的话可以RMQ也可以线段树。

code

#include <bits/stdc++.h>

const int N = 200005;
const int INF = 1000000000;

int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
    while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
    return x * f;
}

int n,a[N],rmq[2][N][20],bin[20],lg[N];

struct Data
{
    int l,r,x,y;

    bool operator < (const Data &p) const
    {
        return a[x] > a[p.x];
    }
};

std::priority_queue<Data> Q;

void pre()
{
    for (int i = 1; i <= n; i += 2) 
        rmq[1][i][0] = i;
    for (int i = 2; i <= n; i += 2) 
        rmq[0][i][0] = i;
    bin[0] = 1;
    for (int i = 1; i <= 17; i++) 
        bin[i] = bin[i - 1] * 2;
    for (int i = 1; i <= n; i++) 
        lg[i] = log(i) / log(2);
    for (int j = 1; j <= lg[n]; j++)
        for (int i = 1; i + bin[j] - 1 <= n; i++)
            rmq[0][i][j] = a[rmq[0][i][j - 1]] < a[rmq[0][i + bin[j - 1]][j - 1]] ? rmq[0][i][j - 1] : rmq[0][i + bin[j - 1]][j - 1],
            rmq[1][i][j] = a[rmq[1][i][j - 1]] < a[rmq[1][i + bin[j - 1]][j - 1]] ? rmq[1][i][j - 1] : rmq[1][i + bin[j - 1]][j - 1];
}

int getMn(int ty,int l,int r)
{
    int w = lg[r - l + 1];
    return a[rmq[ty][l][w]] < a[rmq[ty][r - bin[w] + 1][w]] ? rmq[ty][l][w] : rmq[ty][r - bin[w] + 1][w];
}

Data get(int l,int r)
{
    int p = getMn(l & 1, l, r - 1), q = getMn((p & 1) ^ 1, p + 1, r);
    return (Data){l,r,p,q};
}

int main()
{
    n = read();
    a[0] = INF;
    for (int i = 1; i <= n; i++) 
        a[i] = read();
    pre();
    Q.push(get(1,n));
    for (int i = 1; i <= n / 2; i++)
    {
        Data u = Q.top();
        Q.pop();
        int l = u.l, r = u.r, x = u.x, y = u.y;
        printf("%d %d ",a[x],a[y]);
        if (l < x - 1) 
            Q.push(get(l,x - 1));
        if (x + 1 < y - 1) 
            Q.push(get(x + 1, y - 1));
        if (y + 1 < r) 
            Q.push(get(y + 1, r));
    }
}
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ypxrain/article/details/79962608

Atcoder 080 E - Young Maids

这道题自己原来想出来一个解法,但很遗憾有几点错误。1.编译不通过,显示我的down没有初始化(但是我用的测试数据真的显示我的if()进去了啊)!2.思维确实还不够严密,第二个数必须是在第一个数之后而且...
  • qq_39823695
  • qq_39823695
  • 2017-08-12 18:18:42
  • 95

AtCoder Regular Contest 080 E - Young Maids [拓扑序+分治+奇偶rmq]||[分块]

http://arc080.contest.atcoder.jp/tasks/arc080_c 其实细想其本质是一道拓扑序的题,选了当前点,才能选分裂出的三段。#include #define pb...
  • LZY_Starry
  • LZY_Starry
  • 2017-08-08 12:00:48
  • 257

AtCoder 080E Young Maids

与题意相反,从左往右进行构造。 注意到对每一段区间[L, R]选取最小对{x, y}时,x必须处于与L同奇偶性的位子,而y必须处于与x奇偶性相反的位子。选取最小的x以及最小的y可以用两个RMQ维护原...
  • qq_32506797
  • qq_32506797
  • 2017-08-06 22:52:57
  • 412

ARC080 E - Young Maids

要求串q的字典序最小,那我们倒着,考虑最后插入q开头的字符在p串中的位置x,y(x< y),发现x一定是奇数下标的最小值,y一定是x之后,偶数下标最小值 同时这次操作后,会将区间分为(l,x-1),...
  • L_0_Forever_LF
  • L_0_Forever_LF
  • 2017-10-08 11:30:22
  • 214

[arc080e]Young Maids

题目大意一个长度为偶数的排列p,每次取出相邻两个数并从p中删除,然后将这两个数按顺序加入q的开头(q初始为空)。 问能得到最小字典序的q。做法在堆中保存若干个区间(l,r),以及从中选出最小的和l奇...
  • WerKeyTom_FTD
  • WerKeyTom_FTD
  • 2017-11-03 08:30:46
  • 306

AtCoder Regular Contest 093(E-Bichrome Spanning Tree)

题意: &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;...
  • hnust_Derker
  • hnust_Derker
  • 2018-03-27 18:47:28
  • 75

【搜索】[AtCoder Regular Contest 092 F]Two Faced Edges

题意: 给出一个有向图,对每条边都做一次询问: 反转这条边后,对原图的强连通分量是否有影响? 点的个数N≤1000N≤1000N\leq 1000,边的个数M≤200000M≤200000M\l...
  • qq_34454069
  • qq_34454069
  • 2018-03-18 20:28:57
  • 68

AtCoder Regular Contest 094 E - Tozan and Gezan (博弈论 2个和相同序列双方轮流减一得最后完全相同序列)

Problem StatementYou are given sequences A and B consisting of non-negative integers. The lengths of...
  • deepseazbw
  • deepseazbw
  • 2018-04-09 09:17:04
  • 78

【杂题】[AtCoder Regular Contest 092 E]Both Sides Merger

题意: 给出一个长度为N的数列a,有一些操作,每次操作选择一个数,使得其最终只剩下一个数: 1、选择左端/右端,删去这个数 2、选中中间的一个数,将其值替换为左右两边的数之和,然后删去左右两边的...
  • qq_34454069
  • qq_34454069
  • 2018-03-18 20:09:54
  • 75

AtCoder Beginner Contest 080 C - Shopping Street【暴力枚举】

C - Shopping StreetTime limit : 2sec / Memory limit : 256MBScore : 300 pointsProblem StatementJoisin...
  • nobleman__
  • nobleman__
  • 2017-12-08 16:49:45
  • 77
收藏助手
不良信息举报
您举报文章:AtCoder Regular Contest 080 E - Young Maids
举报原因:
原因补充:

(最多只允许输入30个字)