原题:埃森哲杯第十六届上海大学程序设计联赛春季赛暨上海高校金马五校赛 J
题意:
给定n个数的数组,插入m个数,可以在最前面也可以在最后面,但是一个位置只能插入一个数,使ans最小
ans=max(abs(a[i+1]-a[i]))
解析:
二分ans,对面每个ans,判断是否可以将m个数都插入
问题的怎么判断
既然假设已经知道了ans,那么哪些数可以插在哪些位置就知道了,m个数对应n+1个位置,二分图最大匹配就好了
但是还有一个问题,那些没有插入的位置也有一个val,即位置前后原数组数之差,那么就要改善一下
那些没有插入的地方看成插入一个空的数,问题转化成n+1个位置插入n+1个数
代码:
#include<bits/stdc++.h>
using namespace std;
#define mmm(a,b) memset(a,b,sizeof(a))
int n,m;
int a[209],b[209];
int M[209][209];
//预处理第i个插入项插在第j个空位的val
void init(){//并没有有插入的空和没插入的空的区别,插入的有val,没插入的也有val
for(int i=1;i<=m;i++){
M[i][0]=abs(a[1]-b[i]);
M[i][n]=abs(a[n]-b[i]);
for(int j=1;j<n;j++){
M[i][j]=max(abs(a[j]-b[i]),abs(a[j+1]-b[i]));
}
}
for(int i=m+1;i<=n+1;i++){
M[i][0]=M[i][n]=0;
for(int j=1;j<n;j++){
M[i][j]=abs(a[j]-a[j+1]);
}
}
}
//***********************************************************
int match[209],vis[209];
//插入项序号 1~n+1 (m以后的为空插入项) 空位序号 0~n
int fin(int h,int len){
for(int i=0;i<=n;i++){//试图找到一个可以插入的空
if(vis[i]||M[h][i]>len)continue;
vis[i]=1;
if(match[i]==0||fin(match[i],len)){
match[i]=h;return 1;
}
}
return 0;
}
int judge(int h){//1表示这个间距可以插入
mmm(match,0);
int ans=0;
for(int i=1;i<=n+1;i++){//对于每个插入项
mmm(vis,0);
if(fin(i,h))ans++;
}
if(ans==n+1)return 1;
return 0;
}
//***********************************************************
int main(){
int t;scanf("%d",&t);while(t--){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",a+i);
for(int i=1;i<=m;i++)scanf("%d",b+i);
init();
int l=0,r=1e9+7;
while(r-l>1){
int mid=r+l>>1;
if(judge(mid))r=mid;
else l=mid;
}
printf("%d\n",r);
}
}