Loading

1

首先先简化一下题意,更改最少的籍贯使得\(A\)集合中每个数都能与\(B\)集合中的数一一配对;


我们发现,只修改一个集合即可,这里假设只修改\(B\)集合,考虑如下情景:

两集合均从小到大排好序
\(len\)个数小于等于\(b_{pos}\),我们要把这\(len\)\(a\)\(pos\)\(b\)配对

我们称\(pos\)及其左边为内部,\(pos\)右边为外部
每个\(a_i\)只有两种情况,一种和外部配对,一种和内部配对,设配对到外部的个数\(x\)

考虑一种情况是合法的,当且仅当对于每个\(pos\),都有\(len-x \geq pos\),这样才能保证有足够的数与\(b_1\sim b_{pos}\)都有数与之配对,即\(x\leq len-pos\)

如果理解上面的那些,我们就可以来想一个\(60 pts\)\(n^2\)暴力(实际去捆绑后是96),对于每一个\(b\),我们贪心地从还没被配对的籍贯相同的\(a_j\)配对,然后判断满不满足条件,我们发现关键在于找到\(a_j--b_{i}\)这组配对作为哪些pos的外部,事实上与下列两个条件互为充要:
\(a_j\leq b_{pos}\)
\(pos \lt i\)

于是我们暴力维护即可,满分做法即用线段树维护,叶子结点初值即为\(len-pos\)
鉴于笔者暂不清楚读者水平,在此贴一下代码,有一些细节没在上面讲,在代码中指出,读者可以自己思考一下为什么

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 500;
int read() {
	int x=0;char c=getchar();
	while(c<'0'||c>'9') c=getchar();
	while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
	return x;
}

vector<int > p[N];
int n,l[N],pos[N],siz[N],t[N<<2],tag[N<<2];
struct node {
	int id,w;
}a[N],b[N];

void push_up(int p) { t[p]=min(t[p<<1],t[p<<1|1]); }

void build(int p,int l,int r) {
	if(l==r) {
		t[p]=siz[l];return ;
	}
	int mid=l+r>>1;
	build(p<<1,l,mid),build(p<<1|1,mid+1,r);
	push_up(p);
}

void push_down(int p) {
	if(tag[p]!=0) {
		tag[p<<1]+=tag[p],tag[p<<1|1]+=tag[p];
		t[p<<1|1]+=tag[p],t[p<<1]+=tag[p];
		tag[p]=0;
	}
}

void update(int p,int l,int r,int x,int y,int k) {
	if(x>y) return ;//可能会有越界
	if(x<=l&&r<=y) {
		tag[p]+=k,t[p]+=k;return ;
	}
	push_down(p);
	int mid=l+r>>1;
	if(x<=mid) update(p<<1,l,mid,x,y,k);
	if(y>mid) update(p<<1|1,mid+1,r,x,y,k);
	push_up(p);
}

signed main() {
    cin>>n;
    for(int i=n;i>=1;i--) a[i].id=read(),a[i].w=read();
    for(int i=n;i>=1;i--) b[i].id=read(),b[i].w=read();
    int nw=0;
	for(int i=1;i<=n;i++) {
		l[i]=l[i-1];
    	while(nw<n&&a[nw+1].w<=b[i].w) nw++,l[i]=nw,pos[nw]=i;
    	siz[i]=l[i]-i;
    }
    int ans=0;build(1,1,n);
    for(int i=1;i<=n;i++) {
    	for(int j=l[i-1]+1;j<=l[i];j++) p[a[j].id].push_back(j);
    	if(p[b[i].id].empty()) continue;
    	int r=pos[p[b[i].id].back()];//要取最靠近的,想想为啥
    	update(1,1,n,r,i-1,-1);
    	if(t[1]<0) update(1,1,n,r,i-1,1);
    	else ans++,p[b[i].id].pop_back();p[b[i].id].pop_back(),ans++;
    }
    cout<<n-ans;
    return 0;
}`
posted @ 2024-11-20 14:57  Mortis_Life  阅读(77)  评论(4)    收藏  举报