2019 ICPC World Finals -A-Azulejos

12 篇文章 0 订阅

 

地址:https://judge.icpc.global/problems/azulejos

题目大意:有两排盘子,盘子有价格pi和高度hi。 
盘子的放置规则为:每排的盘子按照价格从小到大排列,对于第二排的盘子的高度必须比第一排对于列的盘子高度高(h2i>h1i)
输入
每排盘子的个数 n
第二排盘子的价格 
第二排盘子的高度
第一排盘子的价格
第一排盘子的高度
输出
若能够按规则放置则输出
第二排盘子的id (id按输入顺序由 1->n) 
第一排盘子的id
否则输出 "impossible" 

思路:贪心+STL (STL大法好啊 ^v^ )
首先对于每排盘子按照价格排序,那么不同价格的盘子的放置顺序已经固定, 
那么问题的关键就是对于不固定盘子(相同价格的盘子)的放置顺序。 
对于两排相同价值的盘子分析 


对第i列有三种情况如图 (长方形表示不固定的盘子集)
一、第二排盘子固定,第一排不固定,利用贪心思想,第一排的盘子放置一个高度最高且小于第二排的盘子高度即为最佳方式
二、一二排的盘子都不固定,那么相同价格盘子的个数少的一排会被消耗掉,则只需要按贪心保证第二排高度大于第一排高度即可 
三、第一排盘子固定,第二排不固定,利用贪心思想,第二排的盘子放置一个高度最低且大于第一排的盘子高度即为最佳方式
先利用map处理出每一排的不同价值盘子的个数并由小到大排序 
对于贪心解法,可以利用二分查找来找出最佳方式,而已经放置的盘子需要去除掉
而set可以进行排序,二分查找以及删除操作,则可以用set结构来存储即可 ( ̄▽ ̄)~* 

Code :

#include<iostream>
#include<algorithm>
#include<map>
#include<set>
using namespace std;
typedef pair<int,int> pr;

const int MAX_N=5e5+5;
int n,T;
int d[2][MAX_N];
map<int,set<pr>> a,b;

int main()
{
	ios::sync_with_stdio(false);
	cin>>n;
	for(int j=0;j<n;++j)
		cin>>d[0][j];
	for(int j=0,x;j<n;++j)
	{
		cin>>x;
		a[d[0][j]].insert({x,j+1});
	}
	for(int j=0;j<n;++j)
		cin>>d[0][j];
	for(int j=0,x;j<n;++j)
	{
		cin>>x;
		b[d[0][j]].insert({x,j+1});
	}
	bool boo=true;
	int a1=0,b1=0;
	int sa,sb,k;
	set<pr> aa,bb;
	set<pr>::iterator si;
	map<int,set<pr>>::iterator ai=a.begin(),bi=b.begin();
	for(int t=0;ai!=a.end()&&boo;)
	{
		if(!a1)	aa=(*ai).second;
		if(!b1)	bb=(*bi).second;
		sa=aa.size();	sb=bb.size();
		if(sa<sb){
			for(auto c:aa)
			{
				si=bb.lower_bound({c.first,0});
				if(si!=bb.begin()){
					d[0][t]=c.second;
					d[1][t]=(*--si).second;
					++t;
					bb.erase(si);
				}else{
					boo=false;	break;
				}
			}
			++ai;
			a1=0;	b1=1;
		}else{
			for(auto c:bb)
			{
				si=aa.lower_bound({c.first+1,0});
				if(si!=aa.end()){
					d[0][t]=(*si).second;
					d[1][t]=c.second;
					++t;
					aa.erase(si);
				}else{
					boo=false;	break;
				}
			}
			++bi;
			a1=1;	b1=0;
		}
	}
	if(boo){
		for(int i=0;i<2;++i)
		{
			for(int j=0;j<n-1;++j)
				cout<<d[i][j]<<" ";
			cout<<d[i][n-1]<<endl;
		}
	}else	cout<<"impossible"<<endl;
	
	return 0;
}

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值