2019 ICPC-WORLD FINAL A-Azulejos 贪心+排序+SET

Ceramic artists Maria and João are opening a small azulejo store in Porto. Azulejos are the beautiful ceramic tiles for which Portugal is famous. Maria and João want to create an attractive window display, but, due to limited space in their shop, they must arrange their tile samples in two rows on a single shelf. Each of João’s tiles has exactly one of Maria’s tiles in front of it and each of Maria’s tiles has exactly one of João’s tiles behind it. These hand-crafted tiles are of many different sizes, and it is important that each tile in the back row is taller than the tile in front of it so that both are visible to passers-by. For the convenience of shoppers, tiles in each row are arranged in non-decreasing order of price from left to right. Tiles of the same price may be arranged in any order subject to the visibility condition stated above.

Your task is to find an ordering of the tiles in each row that satisfies these constraints, or determine that no such ordering exists.

Input

The first line of input contains an integer nn (1≤n≤5⋅1051≤n≤5⋅105), the number of tiles in each row. The next four lines contain nn integers each; the first pair of lines represents the back row of tiles and the second pair of lines represents the front row. Tiles in each row are numbered from 11 to nn according to their ordering in the input. The first line in each pair contains nn integers p1,…,pnp1,…,pn (1≤pi≤1091≤pi≤109 for each ii), where pipi is the price of tile numberii in that row. The second line in each pair contains nn integers h1,…,hnh1,…,hn (1≤hi≤1091≤hi≤109 for each ii), where hihi is the height of tile number ii in that row.

Output

If there is a valid ordering, output it as two lines of nn integers, each consisting of a permutation of the tile numbers from 11 to nn. The first line represents the ordering of the tiles in the back row and the second represents the ordering of the tiles in the front row. If more than one pair of permutations satisfies the constraints, any such pair will be accepted. If no ordering exists, output impossible.

Sample Input 1Sample Output 1
4
3 2 1 2
2 3 4 3
2 1 2 1
2 2 1 3
3 2 4 1
4 2 1 3
Sample Input 2Sample Output 2
2
1 2
2 3
2 8
2 1
impossible

 

 

没错,就是这题签到,THU在比赛的时候卡了两个小时......

从题目难度上来说,就我个人感觉而言,可能就是CF TAG 1800-2000这样的题(也就是蓝名题,手速快能紫的题)

题目大意:

有两排瓷砖,前面一排每一块瓷砖的高度一定要低于后面一排相应位置瓷砖的高度(也就是不能遮挡住),同时两排瓷砖的价格是 in non-decreasing order(一眼过来我甚至觉得无序也行,然后想想还是算了),也就是每一段可以递增也可以保持一水平线(都相等),求一种符合上述要求的可行排列。

思路分析:

嘛这种题一般都要先排个序,按高度排序我们会发现。。并没有什么用,就是浪费时间。

所以我们就按价格排序,排成一个满足题意的价格非递减序列。然后在不改变价格关系的情况下,我们要寻找可行的高度排列方案。因为不能改变价格关系,所以对于同一排的不同价格的瓷砖,我们一定不能改变他们的相对位置。所以我们每一次改变,都只能改变价格相同的一组瓷砖的相对位置。确定这个思路就好办了,由于n是5e5,基本可以猜到复杂度是近似于nlogn级别的了,必要的时间是一个n的循环,那么我们必须在小次数遍历的情况下,通过logn的操作来寻找可行方案。由于贪心策略,我们对每一块不符合条件前排瓷砖,必须在后排找一块刚好比他高一丢丢的瓷砖;反之,对每一块不符合条件前排瓷砖,必须在前排找一块刚好比他矮一丢丢的瓷砖,这就很容易联想到lower_bound和upper_bound。由于每一对瓷砖放好位置之后我们就要删除掉,所以选择有序的方便删除的set容易来处理。

下面附上代码

#include<bits/stdc++.h>
using namespace std;
struct cc
{
    int p,h,num;
}a[500005],b[500005],q;
struct cmp
{
    bool operator()(const cc &L,const cc &R)const{
        if(L.h!=R.h)
        return L.h<R.h;
        else
        return L.num<R.num;
    }
};
set<cc,cmp>s1;
set<cc,cmp>s2;
set<cc,cmp> :: iterator it;
set<cc,cmp> :: iterator itt;
set<cc,cmp> :: iterator mid;
int main()
{
    int n,m,i,j,k,ans,num,sum;
    int sym1,sym2;
        scanf("%d",&n);
        for(i=1;i<=n;i++)
        {
            scanf("%d",&a[i].p);
            a[i].num=i;
        }
        for(i=1;i<=n;i++)
            scanf("%d",&a[i].h);
        for(i=1;i<=n;i++)
        {
            scanf("%d",&b[i].p);
            b[i].num=i;
        }
        for(i=1;i<=n;i++)
            scanf("%d",&b[i].h);
        sort(a+1,a+n+1,[](cc x,cc y){if(x.p!=y.p)return x.p<y.p; else return x.h<y.h;});//这样比光对p排序能快不少(实测0.2s+差距),与set的实现原理有关。
        sort(b+1,b+n+1,[](cc x,cc y){if(x.p!=y.p)return x.p<y.p; else return x.h<y.h;});
        int k1,k2;//其实一个就够了,写两个是我个人习惯问题QAQ
        k1=k2=1;
        sym1=a[1].p,sym2=b[1].p;
        i=j=1;
        while(1)
        {
            for(;i<=n;i++)
            {
                if(a[i].p==sym1) //同组(同p)插入
                    s1.insert(a[i]);
                else
                {
                    sym1=0;
                    break;
                }
            }
            for(;j<=n;j++)
            {
                if(b[j].p==sym2)
                    s2.insert(b[j]);
                else
                {
                    sym2=0;
                    break;
                }
            }
            if(i>n)
                sym1=0;
            if(j>n)
                sym2=0;
                if(sym1==0&&sym2==0)
                {
                    if(s1.size()>s2.size()) //贪心策略,每次对size小的找大的,这样需要遍历的瓷砖就少多了,而且实现简单。
                    {
                        itt=s2.begin();
                        while(itt!=s2.end())
                        {
                            q.h=itt->h;
                            q.num=1000000009;//设为inf,这样it->h一定比q大或者为end
                            it=s1.upper_bound(q);
                            if(it==s1.end())
                            {
                                printf("impossible\n");
                                return 0;
                            }
                            else
                            {
                                b[k2++].num=itt->num;
                                a[k1++].num=it->num;
                                mid=itt;
                                itt++;
                                s1.erase(it);
                                s2.erase(mid);
                            }
                        }
                        sym2=b[j].p;
                    }
                    else
                    {
                        it=s1.begin();
                        while(it!=s1.end())
                        {
                            q.h=it->h;
                            q.num=-1;//设为-inf,这样避免出现itt->h==q.h被排除掉的情况
                            itt=s2.lower_bound(q);
                            if(itt==s2.begin())
                            {
                                printf("impossible\n");
                                return 0;
                            }
                            else
                            {
                                itt--;
                                b[k2++].num=itt->num;
                                a[k1++].num=it->num;
                                mid=it;
                                it++;
                                s1.erase(mid);
                                s2.erase(itt);
                            }
                        }
                        if(s1.size()==s2.size())
                            sym1=a[i].p,sym2=b[j].p;
                        else
                            sym1=a[i].p;
                    }
                    if(i==n+1&&j==n+1)
                        break;
                }
        }

            for(i=1;i<=n;i++)
                printf(i==n?"%d\n":"%d ",a[i].num);
            for(i=1;i<=n;i++)
                printf(i==n?"%d\n":"%d ",b[i].num);
    return 0;
}

 

代码有点挫,大佬轻喷QAQ

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值