Problem A 钥匙
有$n$个人和$m$个钥匙在数轴上,人的坐标为$a_i$,钥匙的坐标为$b_i$
而门的坐标为$p$,要让所有人获得一把不同钥匙,并且到达门,最长时间最短是多少。
对于$100\%$的数据满足$10^3 \leq n \leq 10^3 , n \leq k \leq 2\times 10^3$
Solution :
对于部分数据,可以二分答案然后进行二分图匹配,实测可以通过$80\%$的数据。
事实上,对上面算法的极限复杂度是$O(n^2 k log_2 10^9)$
事实上,我们可以将$nk$中人和钥匙的配对方案求出,排序后,直接从小往大贪心。
这样子复杂度是$O(n \times k \times (\ log_2 n + log_2 k))$的。
# include <bits/stdc++.h> # define int long long using namespace std; const int N=1e6+10; int n,k,p,a[N],b[N]; inline int read() { int X=0,w=0; char c=0; while(c<'0'||c>'9') {w|=c=='-';c=getchar();} while(c>='0'&&c<='9') X=(X<<3)+(X<<1)+(c^48),c=getchar(); return w?-X:X; } int calc(int i,int j) { if (a[i]<=b[j] && b[j]<=p) return p-a[i]; if (a[i]<=p && p<=b[j]) return b[j]-a[i]+b[j]-p; if (b[j]<=a[i] && a[i]<=p) return a[i]-b[j]+p-b[j]; if (b[j]<=p && p<=a[i]) return a[i]-b[j]+p-b[j]; if (p<=a[i] && a[i]<=b[j]) return b[j]-a[i]+b[j]-p; if (p<=b[j] && b[j]<=a[i]) return a[i]-p; } namespace Subtask1 { vector<int>E[N]; bool vis[N]; int pre[N]; bool find(int u) { int sz = E[u].size(); for (int i=0;i<sz;i++) { int v=E[u][i]; if (vis[v]) continue; vis[v]=true; if (pre[v]==-1 || find(pre[v])) { pre[v]=u; return true; } } return false; } int solve() { int ans = 0; memset(pre,-1,sizeof(pre)); for (int i=1;i<=n;i++) { memset(vis,false,sizeof(vis)); if (find(i)) ans++; } return ans; } bool check(int Mid) { for (int i=1;i<=n;i++) E[i].clear(); for (int i=1;i<=n;i++) for (int j=1;j<=k;j++) if (calc(i,j)<=Mid) E[i].push_back(j); int ans = solve(); return (ans==n); } void main() { int l=0,r=2e9,ans; while (l<=r) { int mid = (l+r)>>1; if (check(mid)) r=mid-1,ans=mid; else l=mid+1; } cout<<ans<<'\n'; } } namespace Subtask2 { bool vis1[N],vis2[N]; struct node { int u,v,val; }v[N]; bool cmp (node a,node b) { return a.val<b.val; } void main() { int cnt = 0; for (int i=1;i<=n;i++) for (int j=1;j<=k;j++) v[++cnt]=(node){i,j,calc(i,j)}; sort(v+1,v+1+cnt,cmp); int ans = 0 ; for (int i=1;i<=cnt;i++) { node tmp = v[i]; if (vis1[tmp.u] || vis2[tmp.v]) continue; ans=max(tmp.val,ans); vis1[tmp.u] = vis2[tmp.v] = 1; } printf("%lld\n",ans); } } signed main() { // freopen("key.in","r",stdin); //freopen("key.out","w",stdout); n=read();k=read();p=read(); for (int i=1;i<=n;i++) a[i]=read(); for (int i=1;i<=k;i++) b[i]=read(); if (n*k <= 10000000/3/n) Subtask1::main(); else Subtask2::main(); return 0; }