CF1710E
Rainbow_qwq · · 题解
首先显然地二分答案,
二分图博弈是每个点只能经过一次,题目有个 1000 次,但我们猜它就等于一次的情况。
为了分析方便把
现在要判断
最大匹配感觉不太好做..转成最大独立集?这样就变成了每行、每列只能选 0 或只能选 1。
手玩一下,瞎调整来感受怎样选点最优。显然是上面的若干行列选 0,下面的若干行列选 1。于是方案就是选一个点
这个
去掉一个点大概也是这样选点。其实应该把抠掉的那一行/列移到边界上,但是不移的话也能过,大概是因为判断的结果没有区别吧。
#include<bits/stdc++.h>
#define For(i,a,b) for(int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(int i=(a);i>=(b);--i)
#define int long long
using namespace std;
inline int read()
{
char c=getchar();int x=0;bool f=0;
for(;!isdigit(c);c=getchar())f^=!(c^45);
for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+(c^48);
if(f)x=-x;return x;
}
#define fi first
#define se second
#define pb push_back
#define mkp make_pair
typedef pair<int,int>pii;
typedef vector<int>vi;
#define maxn 200005
#define inf 0x3f3f3f3f
int n,m,a[maxn],b[maxn],pa,pb;
int ca[maxn],sa[maxn],posa[maxn],posb[maxn],cb[maxn],sb[maxn],mid;
int F(int x,int y,int o){
int res=0,p;
if(ca[x]>=y)res+=x*y;
else p=posa[y],res+=p*y+sa[x]-sa[p];
if(cb[y+1]>=n-x)res+=(n-x)*(m-y);
else p=posb[n-x],res+=(n-x)*(m-p+1)+sb[y+1]-sb[p];
res-=o*(pa<=x&&pb<=y&&a[pa]+b[pb]<=mid);
res-=o*(pa>x&&pb>y&&a[pa]+b[pb]>mid);
return res;
}
bool chk()
{
int j=m;
For(i,1,n){
while(j&&a[i]+b[j]>mid)posa[j]=i-1,--j;
ca[i]=j,sa[i]=sa[i-1]+ca[i];
}
while(j)posa[j]=n,--j;
j=1;
cb[m+1]=n+1;
posb[n+1]=m+1;
Rep(i,m,1){
while(j<=n&&b[i]+a[j]<=mid)posb[n-j+1]=i+1,++j;
cb[i]=n-j+1,sb[i]=sb[i+1]+cb[i];
}
while(j<=n)posb[n-j+1]=1,++j;
j=1;
int res1=sb[1],res2=sb[1]-(a[pa]+b[pb]>mid);
For(i,1,n){
while(j<m&&F(i,j,0)<=F(i,j+1,0))++j;
res1=max(res1,F(i,j,0));
}
j=1;
For(i,1,n){
while(j<m&&F(i,j,1)<=F(i,j+1,1))++j;
res2=max(res2,F(i,j,1));
}
return res1==res2;
}
signed main()
{
n=read(),m=read();
For(i,1,n)a[i]=read();
For(i,1,m)b[i]=read();
int a1=a[1],b1=b[1];
sort(a+1,a+n+1),sort(b+1,b+m+1);
pa=lower_bound(a+1,a+n+1,a1)-a,pb=lower_bound(b+1,b+m+1,b1)-b;
int l=0,r=a[pa]+b[pb],res=r;
while(l<=r){
mid=l+r>>1;
if(chk())res=mid,r=mid-1;
else l=mid+1;
}
cout<<res;
return 0;
}