欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

6387. 【NOIP2019模拟2019.10.26】小w与卡牌游戏

程序员文章站 2022-03-13 23:07:44
...

Description

     在昨天玩了数字游戏后,小w觉得不过瘾,叫上了小c一起来玩卡牌游戏。
     小w和小c各有n张扑克牌,每张牌上都有一个数字。游戏共进行n轮,每轮两人各会出一张扑克牌。对于每一轮,牌面上数字大的人获胜并获得一分。鉴于小w是卡牌高手,所以他会让着小c。因此如果两张牌面的数字相同,则小c获胜。
     小w之所以能成为卡牌高手,是因为它有很强的第六感。他可以通过心灵感应获取了小c手上所有卡牌上的数字以及小c的出牌顺序。通过这些信息,小w可以安排自己的出牌顺序以获得尽量多的分数。
     小w把这个任务交给了你,他想要知道一种出牌顺序,使得它的得分最多。特别地,如果有多种合法的出牌顺序,他希望出牌顺序的字典序最大。

Input

     第一行一个整数n,表示游戏的轮数。
     第二行n个整数,表示小c手上的卡牌ci,卡牌按出牌顺序依次给出。
     第三行n个整数,表示小w手上的卡牌wi。

Output

     n个整数,表示得分最高且字典序最大的出牌顺序。

Sample Input

【输入样例1】
5
1 2 3 4 5
1 2 3 4 5

【输入样例2】
5
3 4 5 6 7
1 3 5 7 9
 

Sample Output

【输出样例1】
2 3 4 5 1

【输出样例2】
9 5 7 3 1
 

Data Constraint

对于30%的数据,n<=10
对于另外20%的数据,数据保证只存在一种使小w得分最高的方案
对于100%的数据,n<=1000
数据保证1<=ci,wi<=10^9

Hint

对于第一组样例,小w可以赢得前四局(2>1,3>2,4>3,5>4),输掉最后一局。
注意如果小w按1,2,3,4,5的顺序出牌,他会输掉所有比赛。
对于第二组样例,小w可以赢得前三局。可以证明这是赢得三局的情况下字典序最大的出牌顺序。


Solution

如果没有字典序最大的要求,那么我们可以贪心地解决这个问题。将小c的牌和小w的牌都排序,从大到小考虑w的牌,对于c的每张牌,尽量用最小的w的比这张牌大的牌,如果没有则跳过。如果只有一种合法方案,这种做法可以获得最优解。

时间复杂度O(nlogn),期望得分20,结合枚举所有情况期望得分50。

正解是我们先求出小w的最高得分,然后再解决字典序最大这个要求。对于这个要求,我们可以从前往后一位一位贪心的解决。对于每一位,我们贪心地选择在不影响最高得分的情况下数字最大的牌。这个问题可以通过二分答案再贪心判定解决。对于每一位先二分这位填什么数字,但是要注意二分的时候要将w的牌分为两类,一类是大于a[i]的,由于对答案的贡献都是1,所以当w的牌越大的时候,对后面的出牌就越不优,再结合字典序最大的条件,我们因在合法时将指针向w的更大的牌移,而不合法时向更小的w的牌移;而对于小于等于a[i]的,由于贡献都为0,同样当w越大的时候,对后面出牌越不优。最后对于这个位置之后的其他牌用贪心判定即可。

时间复杂度O(n^2*logn),期望得分100。

 

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define I int
#define ll long long
#define F(i,a,b) for(I i=a;i<=b;++i)
#define Fd(i,a,b) for(I i=a;i>=b;--i)
#define mem(a,b) memset(a,b,sizeof(a))
#define N 1010

using namespace std;
I rd(I &x){
	x=0;I w=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-') w=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
	x*=w;
}
I n,a[N],b[N],c[N],d[N],t,s,l,r,k,mid,ans,tot;
I cmp(I x,I y){return x>y;}
I check(I x,I y){
	I k=0,p=0;
	F(i,1,s){
		if(k+1==x) k++;
		if(k<s&&b[k+1]>c[i]) k++,p++;
	}
	return p+tot+y==t;
}
I main(){
	freopen("card.in","r",stdin);
	freopen("card.out","w",stdout);
	scanf("%d",&n);
	F(i,1,n){scanf("%d",&a[i]),c[i]=-a[i];}
	sort(c+1,c+1+n);
	F(i,1,n) scanf("%d",&b[i]),c[i]=-c[i];
	sort(b+1,b+1+n,cmp);
	F(i,1,n) if(t<n&&b[t+1]>c[i]) t++;
	s=n+1;
	F(i,1,n-1){
		s--;
		F(j,1,s) if(c[j]==a[i]){c[j]=1e9;break;}
		I k=s+1;
		F(j,1,s) if(b[j]<=a[i]){k=j;break;}
		l=1,r=k-1,ans=0;
		while(l<=r){
			mid=(l+r)>>1;
			if(check(mid,1)){ans=mid,r=mid-1;}
			else l=mid+1;
		}
		if(!ans){
			l=k,r=s;
			while(l<=r){
				mid=(l+r)>>1;
				if(check(mid,0)){ans=mid,r=mid-1;}
				else l=mid+1;
			}
		}
		printf("%d ",b[ans]);
		tot+=(b[ans]>a[i]);
		F(j,ans,s-1) b[j]=b[j+1];
		F(j,1,s) if(c[j]==1e9){
			F(k,j,s-1) c[k]=c[k+1];
			break;
		}
	}
	printf("%d ",b[1]);
	return 0;
}


 



作者:zsjzliziyang 
QQ:1634151125 
转载及修改请注明 
本文地址:https://blog.csdn.net/zsjzliziyang/article/details/102788954