Asia Yokohama Regional Contest 2018 K题 - Sixth Sense(思维加贪心加二分)

https://codeforces.com/gym/102082

题意

两个人玩n轮游戏,每次两个人各取一个数,并且已知对手的取数顺序,如果你取的数比他大就算赢一轮,求能赢最多轮次的取法,如果有多种取法输出字典序最大的取法

题解

如果不规定字典序最大随意输出一种那我们可以排下序搞一搞就行了,但现在要保证字典序最大,怎么办呢?有经验的选手就知道,像保证什么最小的情况下求最大以及什么最大的情况求最小这种套路很有可能是二分。对本题来说,我们现在就是要保证当前取法满足条件的情况下字典序最大,我们贪心取当前数最大看后面是否满足,而且数越大后面越不容易满足,换句话说这种取数其实是单调的,所以我们可以二分来做。首先我们要先求出最大可以赢的轮次ans,然后从前往后扫一遍,看当前最多可以拿到多大的bi满足赢的轮次为ans。时间复杂度n^2。

 1 #define IO std::ios::sync_with_stdio(0);
 2 #include <bits/stdc++.h>
 3 #define iter ::iterator
 4 using namespace  std;
 5 typedef long long ll;
 6 typedef pair<ll,ll>P;
 7 #define pb push_back
 8 #define se second
 9 #define fi first
10 #define rs o*2+1
11 #define ls o*2
12 const int N=5e3+5;
13 vector<int>a,b,tmp;
14 int ans,n;
15 int check(int start,int v,vector<int>s){
16     int res=(v>a[start]);
17     int flag=0;
18     int p=s.size()-1;
19     for(int i=start+1;i<n;i++){
20         if(s[p]==v&&!flag){
21             flag=1;
22             p--;
23         }
24         if(s[p]>a[i]){
25             p--;
26             res++;
27         }
28     }
29     return res==ans;
30 }
31 int main(){
32     scanf("%d",&n);
33     a.resize(n);
34     b.resize(n);
35     tmp.resize(n);
36     for(int i=0;i<n;i++){
37         scanf("%d",&a[i]);
38         tmp[i]=a[i];
39     }
40     for(int i=0;i<n;i++){
41         scanf("%d",&b[i]);
42     }
43     sort(b.begin(),b.end());
44     sort(a.begin(),a.end(),greater<int>());
45     multiset<int>s;
46     for(int i=0;i<n;i++){
47         s.insert(b[i]);
48     }
49     multiset<int>iter it;
50     for(int i=0;i<n;i++){
51         it=--s.end();
52         if(*it>a[i])ans++;
53         else it=s.begin();
54         s.erase(it);
55     }
56     for(int i=0;i<n;i++){
57         copy(tmp.begin(),tmp.end(),a.begin());
58         sort(a.begin()+i+1,a.end(),greater<int>());
59         int l=upper_bound(b.begin(),b.end(),a[i])-b.begin()-1;
60         int r=b.size()-1;
61         while(l<r){
62             int m=l+(r-l+1)/2;
63             if(check(i,b[m],b))l=m;
64             else r=m-1;
65         }
66         if(check(i,b[r],b)){
67             if(b[r]>a[i])ans--;
68             printf("%d ",b[r]);
69             b.erase(b.begin()+r);
70         }
71         else{
72             int l=0,r=upper_bound(b.begin(),b.end(),a[i])-b.begin()-1;
73             while(l<r){
74                 int m=l+(r-l+1)/2;
75                 if(check(i,b[m],b))l=m;
76                 else r=m-1;
77             }
78             printf("%d ",b[r]);
79             b.erase(b.begin()+r);
80         }
81     }
82     printf("\n");
83 }

 

转载于:https://www.cnblogs.com/ccsu-kid/p/10604817.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值