一有「字典序最大」什么的的就懵了……这题我颓的std
首先可以发现全局最大得分很好统计,我们令它为 \(k\)
然后我们尝试构造方案,但发现无论怎么放都可能会有后效性
发现对于一个位置,可以放在这里的数有单调性
也即如果有一个比较大的数放在了这里,后面可能就匹配不够 \(k\) 个了
所以我们可以check一下, 对每个位置分两种情况
-
我们找一个 \(a\) 与 \(b[i]\) 形成匹配:
那这时我们二分一个 \(a\) ,check一下去掉这个 \(a\) 后后面还能不能形成 \(k-1\) 个匹配
如果check最后二分出的结果也不能满足,说明这个地方就不能匹配 -
我们找一个 \(a\) ,但它无法与 \(b[i]\) 形成匹配:
二分一个最大的 \(a\) ,且删掉这个 \(a\) 后后面仍能形成 \(k\) 个匹配
然后就是如何check了……可以 \(O(n)\) 跑check
神仙思路:开一棵权值线段树,分别维护这段值域中剩余未匹配a, b的个数及匹配的数量
因为右区间的a一定可以匹配左区间的b,所以这个东西可以合并
然后就每次单点修改删掉一个数,看根节点的匹配个数就行了
- 处理「字典序最大/小的合法方案」(?):如果每个位置的取值有单调性,二分找这里能放的,且这里放了后面仍能满足要求的最大的取值。其实这样的话难点在于check
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n;
int a[N], b[N];
namespace force{
int ans[N], maxn;
void solve() {
sort(a+1, a+n+1);
do {
int cnt=0;
for (int i=1; i<=n; ++i) if (a[i]>b[i]) ++cnt;
if (cnt>=maxn) memcpy(ans+1, a+1, sizeof(int)*n), maxn=cnt;
} while (next_permutation(a+1, a+n+1));
for (int i=1; i<=n; ++i) printf("%d ", ans[i]);
printf("\n");
exit(0);
}
}
namespace task1{
int a2[N], b2[N], ans[N];
int cnt[N];
inline bool cmp(int a, int b) {return a>b;}
bool check(int k) {
int pos=1;
for (int i=1; i<=k; ++i) {
for (; pos<=n; ++pos) {
if (a2[i]>b2[pos]) {
++pos;
goto jump;
}
}
if (pos>n) return 0;
jump: ;
}
return 1;
}
void solve() {
for (int i=1; i<=n; ++i) ++cnt[a[i]];
memcpy(a2, a, sizeof(a));
memcpy(b2, b, sizeof(b));
sort(a2+1, a2+n+1, cmp); sort(b2+1, b2+n+1, cmp);
int l=0, r=n, mid;
while (l<=r) {
mid=(l+r)>>1;
if (check(mid)) l=mid+1;
else r=mid-1;
}
mid=l-1;
//cout<<"mid: "<<mid<<endl;
for (int i=1; i<=mid; ++i) --cnt[a2[i]];
int pos=1;
for (int i=1; i<=mid; ++i) {
for (; pos<=n; ++pos) {
if (a2[i]>b2[pos]) {
ans[pos]=a2[i];
++pos;
goto jump2;
}
}
jump2: ;
}
pos=1;
for (int i=N; ~i; --i)
while (cnt[i]) {
while (ans[pos]) ++pos;
ans[pos]=i;
--cnt[i];
}
for (int i=1; i<=n; ++i) printf("%d ", ans[i]);
printf("\n");
exit(0);
}
}
namespace task{
multiset<int> s;
int tl[N<<2], tr[N<<2], sa[N<<2], sb[N<<2], sum[N<<2], k;
#define tl(p) tl[p]
#define tr(p) tr[p]
#define sa(p) sa[p]
#define sb(p) sb[p]
#define sum(p) sum[p]
void pushup(int p) {
//cout<<"pushup "<<p<<' '<<tl(p)<<' '<<tr(p)<<endl;
//cout<<"sa: "<<sa(p<<1)<<' '<<sa(p<<1|1)<<endl;
//cout<<"sb: "<<sb(p<<1)<<' '<<sb(p<<1|1)<<endl;
int dlt=min(sb(p<<1), sa(p<<1|1));
sum(p)=sum(p<<1)+sum(p<<1|1)+dlt;
sa(p)=sa(p<<1)+sa(p<<1|1)-dlt;
sb(p)=sb(p<<1)+sb(p<<1|1)-dlt;
}
void build(int p, int l, int r) {
tl(p)=l; tr(p)=r;
if (l==r) return ;
int mid=(l+r)>>1;
build(p<<1, l, mid);
build(p<<1|1, mid+1, r);
}
void upd(int p, int pos, int dat, int typ) {
if (tl(p)==tr(p)) {(typ?sa:sb)[p]+=dat; return ;}
int mid=(tl(p)+tr(p))>>1;
if (pos<=mid) upd(p<<1, pos, dat, typ);
else upd(p<<1|1, pos, dat, typ);
pushup(p);
}
void query(int p) {
cout<<"query "<<p<<' '<<tl(p)<<' '<<tr(p)<<' '<<sa(p)<<' '<<sb(p)<<' '<<sum(p)<<endl;
if (tl(p)==tr(p)) return ;
query(p<<1); query(p<<1|1);
}
void solve() {
build(1, 1, N);
for (int i=1; i<=n; ++i) upd(1, a[i], 1, 1), s.insert(a[i]);
for (int i=1; i<=n; ++i) upd(1, b[i], 1, 0);
k=sum(1);
//query(1);
//cout<<"k: "<<k<<endl;
for (int i=1,l,r,mid,rb; i<=n; ++i) {
upd(1, b[i], -1, 0);
l=b[i]+1, r=rb=*s.rbegin();
//cout<<"lr: "<<l<<' '<<r<<endl;
while (l<=r) {
mid=(l+r)>>1;
upd(1, mid, -1, 1);
if (sum(1)==k-1) l=mid+1;
else r=mid-1;
upd(1, mid, 1, 1);
}
if (b[i]+1<=rb) upd(1, l-1, -1, 1);
if (b[i]+1<=rb && sum(1)==k-1) {--k; printf("%d ", l-1); s.erase(s.find(l-1));}
else {
if (b[i]+1<=rb) upd(1, l-1, 1, 1);
l=1, r=b[i];
while (l<=r) {
mid=(l+r)>>1;
upd(1, mid, -1, 1);
if (sum(1)==k) l=mid+1;
else r=mid-1;
upd(1, mid, 1, 1);
}
upd(1, l-1, -1, 1);
printf("%d ", l-1);
//if (s.find(l-1)==s.end()) cout<<"error2"<<endl;
s.erase(s.find(l-1));
}
}
printf("\n");
exit(0);
}
}
signed main()
{
n=read();
for (int i=1; i<=n; ++i) b[i]=read();
for (int i=1; i<=n; ++i) a[i]=read();
//force::solve();
//task1::solve();
task::solve();
return 0;
}