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 = maxlimits_{gcd(i,j) = k} |a_i - b_j| ext{.}
]
(1 leq n leq 10^5)
题解
根据调和级数,我们只需要处理 (c_1)。
考虑分别计算每个 (a_i) 对应的 (b_j) 的最大和最小值。显然这两个问题是对称的。
考虑最大值,整体二分。我们需要判断每个 (a_i) 有没有一个对应的 (b_jin [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<int> divi[N];
int a[N],b[N],c[N];
namespace Task{
int n,ans;
pair<int,int> a[N],b[N];
pair<int,int> 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<int>();
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],"
"[i==n]);
return 0;
}