CodePlus 2019 3月月赛 Div.1 A题 TREE

题意

告诉你一个数组\(h\),然后每次给你询问一个区间\(l,r\),问你$$\prod_{i=1}l\prod_{j=i+1}rGCD(h[i],h[j])$$

题解

这个区间查询感觉不好维护,实在找不到用啥东西去维护,而且他又没修改,我考虑的是使用莫队,然后考虑莫队扩展缩小区间的时候怎么搞:扩展的时候就给答案乘上新位置上的数与现在区间中所有数的GCD,缩区间同理;但是这样搞好像也不好搞,然后把数拆了,拆成唯一分解的样子,然后\(O(因子个数)\)的去查对应的贡献,修改的时候话因为数的大小跟\(n\)同阶的所以每次是\(O(5*logn)\)(\(5\)是最多的因子个数)去给对应的质因子的多少次方乘上贡献;缩区间的时候就是除(乘逆元);但是这样过不去,修改复杂度太高了,但是这种修改的查询是可以差分的,所以考虑莫队二次离线差分询问;参考这篇文章;
总的时间复杂度是\(O(n*5*logn+(n+m)*\sqrt n*5+n*logn)\),最后那个\(nlog\)是在\(O(1)\)算贡献的时候要去快速幂搞逆元,前面你预处理因子就线性筛,然后只拿质因子去做埃氏筛然后对每个数去除一哈看看是质因子的多少次方,复杂度大概是\(O(n+nloglogn*x)\)后面那个\(x\)是每个数是他质因子的多少次方,我不知道该咋算;
不是正解,但是过了,正解是\(O(n\sqrt n)\)的,tql;

#include<bits/stdc++.h>
#define Fst first
#define Snd second
#define RG register
#define mp make_pair
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long LL;
typedef long double LD;
typedef unsigned int UI;
typedef unsigned long long ULL;
template<typename T> inline void read(T& x) {
	char c = getchar();
	bool f = false;
	for (x = 0; !isdigit(c); c = getchar()) {
		if (c == '-') {
			f = true;
		}
	}
	for (; isdigit(c); c = getchar()) {
		x = x * 10 + c - '0';
	}
	if (f) {
		x = -x;
	}
}
template<typename T, typename... U> inline void read(T& x, U& ... y) {
	read(x), read(y...);
}
const int MAX=1e5,N=MAX+10,P=998244353,mlog=17;
int pri[N];
bool sign[N];
int n,m,K,cnt;
int H[N],part[N];
int Sum[N][20];
int S0[N],S1[N],ML[N],MR[N],ANS[N];
struct Data {
	int l,r,id;
	Data () {}
	Data (int a,int b,int c) :l(a),r(b),id(c) {}
}Q[N];
vector<Data> G[N][2];
struct PR {
	int v,t;
};
vector<PR> V[N];
void Prepare() {
	for(int i=2;i<=MAX;++i) {
		if(!sign[i]) pri[++cnt]=i;
		for(int j=1;i*pri[j]<=MAX;++j) {
			sign[i*pri[j]]=true;
			if(i%pri[j]==0) break;
		}
	}
	for(int i=1;i<=cnt;++i) {
		for(int j=pri[i];j<=MAX;j+=pri[i]) {
			int x=j,t=0;
			while(x%pri[i]==0) x/=pri[i],++t;
			V[j].push_back((PR){pri[i],t});
		}
		for(int j=1;j<=mlog;++j) Sum[pri[i]][j]=1;
	}
}
bool cmp(Data A,Data B) {
	return part[A.l]==part[B.l]?A.r<B.r:part[A.l]<part[B.l];
}
int Pow(int a,int k) {
	int res=1;
	for(int i=k;i;i>>=1) {
		if(i&1) res=1ll*res*a%P;
		a=1ll*a*a%P;
	}
	return res;
}
//#define rua
int main() {
//	ios::sync_with_stdio(false);
#ifdef rua
	freopen("GG.in","r",stdin);
#endif
	Prepare();
	read(n,m);
	int Base=sqrt(n),ID=1,now=0;
	for(int i=1;i<=n;++i) {
		read(H[i]); part[i]=ID;
		if(now==Base-1) ++ID,now=0;
		else ++now;
	}
	for(int i=1;i<=m;++i) read(Q[i].l,Q[i].r),Q[i].id=i;
	sort(Q+1,Q+m+1,cmp);
	int L=Q[1].r+1,R=Q[1].r;
	for(int i=1;i<=m;++i) {
		if(L<Q[i].l) G[R][0].push_back(Data(L,Q[i].l-1,i));
		else if(L>Q[i].l) G[R][0].push_back(Data(Q[i].l,L-1,i));
		L=Q[i].l;
		if(R<Q[i].r) G[L-1][1].push_back(Data(R+1,Q[i].r,i));
		else if(R>Q[i].r) G[L-1][1].push_back(Data(Q[i].r+1,R,i));
		R=Q[i].r;
		ML[i]=MR[i]=1;
	}
	S0[0]=S1[0]=1;
	for(int i=1;i<=n;++i) {
		S0[i]=S0[i-1]; S1[i]=S1[i-1];
		for(auto dt: V[H[i]]) {
			int v=dt.v,t=dt.t;
			S0[i]=1ll*S0[i]*Sum[v][t]%P;
			for(int j=1;j<=mlog;++j) Sum[v][j]=1ll*Sum[v][j]*Pow(v,min(j,t))%P;
			S1[i]=1ll*S1[i]*Sum[v][t]%P;
		}
		for(auto t: G[i][0]) {
			ML[t.id]=1;
			for(int	j=t.l;j<=t.r;++j) {
				for(auto dt: V[H[j]]) {
					ML[t.id]=1ll*ML[t.id]*Sum[dt.v][dt.t]%P;
				}
			}
		}
		for(auto t: G[i][1]) {
			MR[t.id]=1;
			for(int j=t.l;j<=t.r;++j) {
				for(auto dt: V[H[j]]) {
					MR[t.id]=1ll*MR[t.id]*Sum[dt.v][dt.t]%P;
				}
			}
		}
	}
	L=Q[1].r+1; R=Q[1].r;
	int res=1;
	for(int i=1;i<=m;++i) {
		if(L<Q[i].l) res=1ll*res*Pow(1ll*ML[i]%P*Pow(1ll*S1[Q[i].l-1]*Pow(S1[L-1],P-2)%P,P-2)%P,P-2)%P;
		else if(L>Q[i].l) res=1ll*res*ML[i]%P*Pow(1ll*S1[L-1]*Pow(S1[Q[i].l-1],P-2)%P,P-2)%P;
		L=Q[i].l;
		if(R<Q[i].r) res=1ll*res*S0[Q[i].r]%P*Pow(S0[R],P-2)%P*Pow(MR[i],P-2)%P;
 else if(R>Q[i].r) res=1ll*res*Pow(1ll*S0[R]%P*Pow(S0[Q[i].r],P-2)%P*Pow(MR[i],P-2)%P,P-2)%P;
        R=Q[i].r;
        ANS[Q[i].id]=res;
	}
	for(int i=1;i<=m;++i) printf("%d\n",ANS[i]);
	return 0;
}
posted @ 2019-03-12 20:25  Sachiko  阅读(179)  评论(0编辑  收藏  举报