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;
}