构造、贪心、二分

已知 $a_i + d_{i}^{\min}$ 在 $b$ 中出现,考虑怎么得到 $d_{i}^{\min}$ 的值。

最优情况自然是 $b_1=a_i + d_{i}^{\min}$,但是有可能 $a_i > b_1$,所以二分出第一个不小于 $a_i$ 的元素 $b_j$ 即可得到 $d_{i}^{\min} = b_j - a_i$。

接下来考虑怎么得到 $d_{i}^{\max}$ 的值。最优情况为 $b_n=a_i + d_{i}^{\max}$。但如果 $a_i + d_{i}^{\max} = b_j$ 则需要让所有 $a_k(k \in [i+1,j])$ 能对应 $b_{k-1}$,否则 $a_i$ 无法对应到 $b_j$。

如果 $a_k \leq b_{k-1}$ 那么能够对应,这部分可以用前缀和加二分维护以得到最大的满足 $a_k(k \in [i+1,j])$ 都能和 $b_{k-1}$ 对应的 $j$ 的值。

时间复杂度 $O(n \log n)$。

#include<bits/stdc++.h>
using namespace std;
int n,a[200'005],b[200'005],sum[200'005];
void solution(){
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++) cin>>b[i];
    for(int i=1;i<=n;i++) cout<<*lower_bound(b+1,b+n+1,a[i])-a[i]<<" \n"[i==n];
    for(int i=1;i<=n;i++) sum[i]=sum[i-1]+(a[i]<=b[i-1]);
    for(int i=1;i<=n;i++){
        int l=i,r=n,ans=i;
        while(l<=r){
            int mid=(l+r)>>1;
            if(sum[mid]-sum[i]!=mid-i) r=mid-1;
            else ans=mid,l=mid+1;
        }
        cout<<b[ans]-a[i]<<" \n"[i==n];
    }
}
int T;
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    cin>>T;
    while(T--) solution();
    return 0;
}
最后修改:2024 年 08 月 06 日
如果觉得我的文章对你有用,请随意赞赏