Gym102354B Yet Another Convolution

Yet Another Convolution

You are given an integer array \(a_1, \dots, a_n\) and an integer array \(b_1, \dots, b_n\).

You have to calculate the array \(c_1, \dots, c_{n}\) defined as follows:

\[ c_k = \max\limits_{\gcd(i,j) = k} |a_i - b_j|\text{.} \]

\(1 \leq n \leq 10^5\)

题解

根据调和级数,我们只需要处理 \(c_1\)

考虑分别计算每个 \(a_i\) 对应的 \(b_j\) 的最大和最小值。显然这两个问题是对称的。

考虑最大值,整体二分。我们需要判断每个 \(a_i\) 有没有一个对应的 \(b_j\in [l,r]\)

考虑莫比乌斯反演,\(\sum_{d|i,d|j}\mu(d)\),那么开个cnt数组

对于每个j, for d|j, cnt[d]+=mu[d]
对于每个i, for d|i, sum+=cnt[d]

如果sum>0就说明存在对应的 \(b_j\)

时间复杂度 \(O(n \ln n \log v)\)

CO int N=1e5+10,inf=1e9;
int pri[N],tot,mu[N];
vector divi[N];
int a[N],b[N],c[N];

namespace Task{
    int n,ans;
    pair a[N],b[N];
    pair ta[N],tb[N];
    int cnt[N];
    
    void solve_min(int la,int ra,int lb,int rb,int lv,int rv){
        if(la>ra or lb>rb) return;
        if(lv==rv){
            for(int i=la;i<=ra;++i) ans=max(ans,a[i].first-lv);
            return;
        }
        int mv=(lv+rv)>>1;
        int ql=lb,qr=rb;
        for(int i=lb;i<=rb;++i){
            if(b[i].first<=mv){
                for(int d:divi[b[i].second]) cnt[d]+=mu[d];
                tb[ql++]=b[i];
            }
            else tb[qr--]=b[i];
        }
        int mb=ql-1;
        ql=la,qr=ra;
        for(int i=la;i<=ra;++i){
            int sum=0;
            for(int d:divi[a[i].second]) sum+=cnt[d];
            if(sum) ta[ql++]=a[i];
            else ta[qr--]=a[i];
        }
        int ma=ql-1;
        for(int i=lb;i<=rb;++i)if(b[i].first<=mv)
            for(int d:divi[b[i].second]) cnt[d]-=mu[d];
        copy(ta+la,ta+ra+1,a+la);
        copy(tb+lb,tb+rb+1,b+lb);
        solve_min(la,ma,lb,mb,1,mv);
        solve_min(ma+1,ra,mb+1,rb,mv+1,rv);
    }
    void solve_max(int la,int ra,int lb,int rb,int lv,int rv){
        if(la>ra or lb>rb) return;
        if(lv==rv){
            for(int i=la;i<=ra;++i) ans=max(ans,rv-a[i].first);
            return;
        }
        int mv=(lv+rv+1)>>1;
        int ql=lb,qr=rb;
        for(int i=lb;i<=rb;++i){
            if(b[i].first>=mv){
                for(int d:divi[b[i].second]) cnt[d]+=mu[d];
                tb[qr--]=b[i];
            }
            else tb[ql++]=b[i];
        }
        int mb=qr+1;
        ql=la,qr=ra;
        for(int i=la;i<=ra;++i){
            int sum=0;
            for(int d:divi[a[i].second]) sum+=cnt[d];
            if(sum) ta[qr--]=a[i];
            else ta[ql++]=a[i];
        }
        int ma=qr+1;
        for(int i=lb;i<=rb;++i)if(b[i].first>=mv)
            for(int d:divi[b[i].second]) cnt[d]-=mu[d];
        copy(ta+la,ta+ra+1,a+la);
        copy(tb+lb,tb+rb+1,b+lb);
        solve_max(ma,ra,mb,rb,mv,rv);
        solve_max(la,ma-1,lb,mb-1,lv,mv-1);
    }
    int main(){
        ans=0;
        solve_min(1,n,1,n,1,inf);
        solve_max(1,n,1,n,1,inf);
        return ans;
    }
}

int main(){
    int n=read();
    mu[1]=1;
    for(int i=2;i<=n;++i){
        if(!pri[i]) pri[++tot]=i,mu[i]=-1;
        for(int j=1;j<=tot and i*pri[j]<=n;++j){ // edit 1: ++j
            pri[i*pri[j]]=1;
            if(i%pri[j]==0){
                mu[i*pri[j]]=0;
                break;
            }
            mu[i*pri[j]]=-mu[i];
        }
    }
    for(int i=1;i<=n;++i)
        for(int j=1;j<=n/i;++j) divi[j*i].push_back(i);
    for(int i=1;i<=n;++i) read(a[i]);
    for(int i=1;i<=n;++i) read(b[i]);
    for(int i=1;i<=n;++i){
        Task::n=n/i;
        for(int j=1;j<=Task::n;++j) Task::a[j]={a[j*i],j};
        for(int j=1;j<=Task::n;++j) Task::b[j]={b[j*i],j};
        c[i]=Task::main();
    }
    for(int i=1;i<=n;++i) printf("%d%c",c[i]," \n"[i==n]);
    return 0;
}

你可能感兴趣的:(Gym102354B Yet Another Convolution)