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 = 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;
}
原文地址:https://www.cnblogs.com/autoint/p/12298870.html