CF1028H Make Square

*2900!

考虑把每个数质因数分解,每个质数指数模 \(2\),对于 \(x,y\) 的答案是什么?是不是假如 \(2\) 边的质数指数只有 \(1\) 个为 \(1\) 的质数个数。

具体的,记 \(f_x\)\(x\) 分解后指数模 \(2\)\(1\) 的个数,那么 \(f_x+f_y\) 是不是 \(2\) 边同时为 \(1\) 就不需要减去?如何保留 \(2\) 边共同的 \(1\)?显然 \(\gcd(x,y)\),所以 \(ans=f_x+f_y-2f_{\gcd(x,y)}\)

考虑 \(5e6\) 内质数个数最多 \(7\) 个,因为从 \(2\) 开始连续 \(8\) 个质数积大于 \(5e6\)

那么 \(\max{d(a_i)}=2^7,i\in n\)

接下来自然想到枚举 \(\gcd\),因为每个数的约数不多,显然需要上一个数 \(y,d|a_y\) 的位置,又因为答案跟 \(f\) 有关,\(f\) 最大为 \(7\),考虑扫描线,到 \(i\) 时枚举约数,再定义 \(f_{i,j}\) 为当前扫描下, \(\gcd\)\(j\) 时,满足 \(j|a_x\) 的最大 \(x\)。那么只要枚举一下就好了,接下来变成一个更新操作有 \(n*7*128\) 次,查询操作有 \(m\) 次的单点更新,区间最小值,发现是不平衡的。我们直接使用 \(O(1)\) 修改,\(O(\sqrt{n})\) 查询分块即可。

这里补一个东西:

假如 \(\gcd(x,y)=d\),但是枚举到 \(k,k|d\) 时,因为 \(f_k<f_d\) 所以显然不会对最小值有影响。

不过确实跑的挺慢的(发现忘了关同步流,关了之后还是能在时限一半内通过的)。

#include <bits/stdc++.h>
//#define int long long
#define pb push_back
using namespace std;
const int N=(int)(1e6+5),M=5040000;
bool vis[M];
int pri[M>>1],cnt;
int n,m,a[N],f[M];

namespace MI {
	int mi[1000],val[N],id[N],bl,L[1000],R[1000];
	void init() {
		bl=sqrt(n);
		for(int i=1;i<=n;i++) id[i]=(i-1)/bl+1;
		for(int i=1;i<=id[n];i++) mi[i]=0x3f3f3f3f,L[i]=(i-1)*bl+1,R[i]=i*bl; R[id[n]]=n;
		for(int i=1;i<=n;i++) val[i]=0x3f3f3f3f;
	}
	void upt(int x,int v) {
		val[x]=min(val[x],v);
		mi[id[x]]=min(mi[id[x]],v);
	}
	int qry(int l,int r) {
		if(id[l]==id[r]) {
			int res=0x3f3f3f3f;
			for(int i=l;i<=r;i++) res=min(res,val[i]);
			return res;
		} else {
			int res=0x3f3f3f3f;
			for(int i=l;i<=R[id[l]];i++) res=min(res,val[i]);
			for(int i=id[l]+1;i<id[r];i++) res=min(res,mi[i]);
			for(int i=L[id[r]];i<=r;i++) res=min(res,val[i]);
			return res;
		}
	}
}

void init() {
	for(int i=2;i<=M-5;i++) {
		if(!vis[i]) pri[++cnt]=i;
		for(int j=1;j<=cnt&&pri[j]*i<=M-5;j++) {
			vis[i*pri[j]]=1;
			if(i%pri[j]==0) break ; 
		}
	}
}

int gcd(int x,int y) {
	return !y?x:gcd(y,x%y);
}
vector<pair<int,int> >vec[N];
int tmp[10],ans[N*5],sum[N],st[20][N];
vector<int>vecd[N]; 

inline int qry(int l,int r) {
	int qwq=log2(r-l+1);
	return min(st[qwq][l],st[qwq][r-(1<<qwq)+1]);
}

int mp[8][M];
signed main() {
	cin.tie(0); ios::sync_with_stdio(false);
	cin>>n>>m; init();
	for(int i=1;i<=n;i++) {
		int x,sz=0; cin>>x; int res=1;
		for(int j=1;j<=cnt&&pri[j]*pri[j]<=x;j++) {
			if(x%pri[j]) continue ;
			int qwq=0;
			while(x%pri[j]==0) x/=pri[j],++qwq;
			if(qwq&1) tmp[++sz]=pri[j],res*=pri[j];
		}
		if(x!=1) res*=x,tmp[++sz]=x;
		for(int S=1;S<=(1<<sz)-1;S++) {
			int qwq=1;
			for(int j=0;j<sz;j++) {
				if((S>>j)&1) {
					qwq*=tmp[j+1];
				}
			}
//			++mp[qwq]; if(mp[qwq]==2) vecd.pb(qwq);
			vecd[i].pb(qwq);
		}
		vecd[i].pb(1);
		if(res!=1) a[i]=res;
	}
	for(int i=1;i<=M-5;i++) {
		int x=i,num=0;
		for(int j=1;j<=cnt&&pri[j]*pri[j]<=x;j++) {
			if(x%pri[j]) continue ;
			int qwq=0;
			while(x%pri[j]==0) x/=pri[j],++qwq;
			if(qwq&1) ++num;
		}
		if(x!=1) ++num;
		f[i]=num;
	}
	memset(ans,0x3f,sizeof(ans));
	memset(st,0x3f,sizeof(st));
	for(int i=1;i<=n;i++) sum[i]=sum[i-1]+(a[i]==0);
	for(int i=1;i<=n;i++) {
		if(!a[i]) st[0][i]=0x3f3f3f3f;
		else st[0][i]=f[a[i]];
	}
	for(int i=1;(1<<i)<=n;i++) {
		for(int j=1;j+(1<<i)-1<=n;j++) {
			st[i][j]=min(st[i-1][j],st[i-1][j+(1<<(i-1))]);
		}
	}
	for(int i=1;i<=m;i++) {
		int x,y; cin>>x>>y; 
		if(sum[y]-sum[x-1]>=2) ans[i]=0;
		else if(sum[y]-sum[x-1]==1) {
			ans[i]=qry(x,y);
		}
		vec[y].pb(make_pair(x,i));
	}
	MI::init();
	for(int i=1;i<=n;i++) {
		for(int d:vecd[i]) {
			for(int j=0;j<=7;j++) {
				int p=mp[j][d];
				if(p) MI::upt(mp[j][d],f[a[i]]+f[a[p]]-2*f[d]);
			}
		}
		for(int d:vecd[i]) {
			mp[f[a[i]]][d]=i;
		}
		for(auto x:vec[i]) ans[x.second]=min(ans[x.second],MI::qry(x.first,i));
	}
	for(int i=1;i<=m;i++) cout<<ans[i]<<'\n';
	return 0;
}

posted @ 2022-07-14 19:25  FxorG  阅读(21)  评论(0编辑  收藏  举报