上海高校金马五校赛 J 小y写文章

传送门

题意:太懒了,去原题看吧。


题解:最大值最小,明显的二分痕迹,于是果断二分最大值。check的话,可以比较明显看出是一个匹配问题,n个数字,共产生了n+1个空位,现在有m个数字要全部填进去,我们可以nm的建立数字-空位的边,然后单独再考虑一下最前最后两个空位,但是这样的匹配是n+1和m匹配,不能处理那些不填数字的空位,于是我们建立n+1-m个“空点”,某个空位如果不填数字也合法的时候,就网每个空点都连边,这样存在解就等价于存在完美匹配。由于是完美匹配,我们跑匈牙利的时候,某个点不存在匹配方案就可以提前返回false,不这样优化会超时。

Code:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 205;
typedef long long LL;
int A[maxn],B[maxn];
int n,T,m;
int a[maxn],b[maxn];
int vis[maxn];
int first[maxn],nxt[maxn*maxn],des[maxn*maxn],tot;
inline void addEdge(int x,int y){
    tot++;
    des[tot] =y;
    nxt[tot] = first[x];
    first[x] = tot;
}
int path(int u,int flag){
    for (int t = first[u];t;t=nxt[t]){
        int v = des[t];
        if (vis[v]!=flag){
            vis[v]=flag;
            if (b[v]==-1||path(b[v],flag)){
                a[u]=v;
                b[v]=u;
                return 1;
            }
        }
    }
    return 0;
}
bool maxMatch(){
    memset(a,-1,sizeof a);
    memset(b,-1,sizeof b);
    memset(vis,-1,sizeof vis);
    int res =0;
    for (int i=0;i<=n;i++){
        if (a[i]==-1){
            if(path(i,i))continue;
            else return false;
        }
    }
    return true;
}
bool check(int x){
    tot=0;
    memset(first,0,sizeof first);
    for (int i=1;i<n;i++){
        int temp = abs(A[i-1]-A[i]);
        if (temp<=x){
            for (int k = m;k<=n;k++){
                addEdge(i,k);
            }
        }
        for (int j=0;j<m;j++){
            int temp = max(abs(B[j]-A[i]),abs(B[j]-A[i-1]));
            if (temp<=x){
                addEdge(i,j);
            }
        }
    }
    for (int i=0;i<m;i++){
        int temp = abs(A[0]-B[i]);
        if (temp<=x){
            addEdge(0,i);
        }
        temp = abs(A[n-1]-B[i]);
        if (temp<=x){
            addEdge(n,i);
        }
    }
    for (int i=m;i<=n;i++){
        addEdge(0,i);
        addEdge(n,i);
    }
    return maxMatch();
}
void solve(){
    scanf("%d%d",&n,&m);
    int Amax =0;
    int Amin = 0x3f3f3f3f;
    int Bmax =0;
    int Bmin = 0x3f3f3f3f;
    for (int i=0;i<n;i++){
        scanf("%d",A+i);
        Amax = max(Amax,A[i]);
        Amin = max(Amin,A[i]);
    }
    for (int i=0;i<m;i++){
        scanf("%d",B+i);
        Bmax = max(Bmax,B[i]);
        Bmin = max(Bmin,B[i]);
    }
    LL l =0;
    LL r = max(abs(Bmax-Amin),abs(Bmin-Amax));
    while (r-l>1){
        LL mid = l+r >>1;
        if (check(mid)){
            r = mid;
        }else{
            l = mid;
        }
    }
    if (check(l)){
        printf("%d\n",l);
    }else{
        printf("%d\n",r);
    }
}
int main(){
    cin>>T;
    while (T--){
        solve();
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/calabash_boy/article/details/79954628