題意:
- A和B在打牌,B足夠聰明,他能知道A的出牌順序,現在決定B的出牌順序,使得B出的牌能最多的比A出的牌大,如果有多個方案,則輸出最大字典序
題解
- 首先我們先求出最多能幾張牌大於A的出牌,然後從A的第一張牌開始儘可能的用最大的牌,同時又不會破壞最多大於的,我們可以考慮如果當前選的牌是大於A[i]的,那麼如果我把選的牌再變大,則滿足最多的可能性會越來越小,所以是存在單調性的,這樣我們就可以用二分來找出如果是要大於A[i]的最大牌而且又不會使得後面的最多大於被破壞,同時對於只能選小於或等於A[i]的牌,但我們選的牌越大,則滿足最多的可能性就會越來越小,所以也是存在單調性的,所以這道題就分類二分就好了(對於滿足一種性質,又要滿足最大或最小,一般要用到二分)
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+9;
int a[maxn],b[maxn],tmp[maxn];
int res;
int n;
bool check(int id, int x, vector<int> G){
int ans = (tmp[id] < G[x]);
int l = n , r = G.size()-1;
while(l > id && r>=0){
if(r == x)r--;
if(tmp[l] < G[r]){
ans++; l--; r--;
}
else l--;
}
return ans == res;
}
int main(){
while(~scanf("%d",&n)){
vector<int> G;
for(int i = 1; i <= n; i++)scanf("%d",&a[i]),tmp[i]=a[i];
for(int i = 1; i <= n; i++)scanf("%d",&b[i]),G.push_back(b[i]);
sort(b+1,b+1+n);
sort(tmp+1,tmp+1+n);
int l,r;
l = r = n;
res = 0;
while(l&&r){
if(tmp[l] < b[r]){
--r; --l; res++;
}
else --l;
}
sort(G.begin(),G.end());
for(int i = 1; i <= n; i++){
copy(a+1,a+1+n,tmp+1);
sort(tmp+i+1,tmp+1+n);
int l = upper_bound(G.begin(),G.end(),a[i])-G.begin();
int r = G.size()-1;
while(l < r){
int mid = l+(r-l+1)/2;
if(check(i,mid,G)) l = mid;
else r = mid-1;
}
if(check(i,r,G)){
if(a[i] < G[r])res--;
printf("%d",G[r]);
G.erase(G.begin()+r);
}
else{
int l = 0,r = upper_bound(G.begin(),G.end(),a[i])-G.begin()-1;
while(l<r){
int mid = l+(r-l+1)/2;
if(check(i,mid,G))l=mid;
else r=mid-1;
}
if(a[i] < G[r])res--;
printf("%d",G[r]);
G.erase(G.begin()+r);
}
if(i<n)printf(" ");
else printf("\n");
}
}
return 0;
}