【2019.8.11下午 慈溪模拟赛 T2】数数(gcd)(分块+枚举因数)

莫比乌斯反演

考虑先推式子:

[sum_{i=l}^r[gcd(a_i,G)=1] ]

[sum_{i=l}^rsum_{p|a_i,p|G}mu(p) ]

[sum_{p|G}mu(p)sum_{i=l}^r[p|a_i] ]

因此我们只要枚举询问的这个数的因数,然后求出这段区间内有多少个数是它的倍数即可。

分块

我们可以统计对于每个数,每个块内有多少个数是其倍数。

数的规模(O(n)),块大小(O(sqrt n)),所以内存是(O(nsqrt n)),询问是(O(sqrt n)),修改是(O(1))

但由于询问和修改都需要枚举因数,因此时间复杂度还要乘上一个数的不含平方因子的因数个数,这个最大是(60)左右。

因此复杂度是(O(60nsqrt n))

代码

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 50000
#define V 100000
using namespace std;
int n,a[N+5];
class FastIO
{
	private:
		#define FS 100000
		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
		#define pc(c) (C==E&&(clear(),0),*C++=c)
		#define tn (x<<3)+(x<<1)
		#define D isdigit(c=tc())
		int T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
	public:
		I FastIO() {A=B=FI,C=FO,E=FO+FS;}
		Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
		Tp I void write(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
		Tp I void writeln(Con Ty& x) {write(x),pc('
');}
		I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
}F;
class BlockSolver//分块
{
	private:
		template<int SZ> class LinearSiever//线性筛
		{
			private:
				int Pt,P[SZ+5]; 
			public:
				int mu[SZ+5];
				I LinearSiever()
				{
					mu[1]=1;for(RI i=2,j;i<=SZ;++i)
						for(!P[i]&&(mu[P[++Pt]=i]=-1),j=1;1LL*i*P[j]<=SZ;++j)
							if(P[i*P[j]]=1,i%P[j]) mu[i*P[j]]=-mu[i];else break;
				}
		};LinearSiever<V> L;
		template<int SZ,int BT,int BS> class Block//分块
		{
			private:
				int bl[SZ+5],s[BT+5][SZ+5];
			public:
				I Block() {for(RI i=1;i<=SZ;++i) bl[i]=(i-1)/BS+1;}//初始化
				I void Upt(CI p,CI x,CI y) {s[bl[p]][x]+=y;}//单点修改
				I int Qry(CI l,CI r,CI k)//区间询问
				{
					#define BF(x,y) for(RI i=x,t=y;i<=t;++i) res+=!(a[i]%k);
					RI res=0;if(bl[l]==bl[r]) {BF(l,r);return res;}
					BF(l,bl[l]*BS);BF((bl[r]-1)*BS+1,r);
					for(RI i=bl[l]+1;i^bl[r];++i) res+=s[i][k];return res;
				}
		};Block<V,500,300> B;
		int sz[V+5],v[V+5][80];
	public:
		I void Solve()
		{
			RI Qt,i,j,op,x,y,z,t;for(i=1;i<=V;++i) for(j=1;j*j<=i;++j)
				!(i%j)&&(L.mu[j]&&(v[i][++sz[i]]=j),(j*j)^i&&L.mu[i/j]&&(v[i][++sz[i]]=i/j));//预处理每个数不含平方因子的因数
			for(i=1;i<=n;++i) for(j=1;j<=sz[a[i]];++j) B.Upt(i,v[a[i]][j],1);//预处理
			F.read(Qt);W(Qt--)
			{
				if(F.read(op),F.read(x),F.read(y),op==1)//修改
				{
					for(i=1;i<=sz[a[x]];++i) B.Upt(x,v[a[x]][i],-1);a[x]=y;//删去原贡献
					for(i=1;i<=sz[a[x]];++i) B.Upt(x,v[a[x]][i],1);//更新新贡献
				}
				else
				{
					for(F.read(z),t=0,i=1;i<=sz[z];++i) t+=L.mu[v[z][i]]*B.Qry(x,y,v[z][i]);//枚举因数统计答案
					F.writeln(t);//输出答案
				}
			}
		}
}S;
int main()
{
	freopen("gcd.in","r",stdin),freopen("gcd.out","w",stdout);
	RI i;for(F.read(n),i=1;i<=n;++i) F.read(a[i]);return S.Solve(),F.clear(),0;
}
原文地址:https://www.cnblogs.com/chenxiaoran666/p/Contest20190811afternoonT2.html