#莫队,根号分治#洛谷 5071 [Ynoi2015] 此时此刻的光辉

题目传送门


分析

约数个数就是 \(\prod{(c+1)}\),但是带 \(log\) 会TLE,
考虑将每个数分成 \(\leq \sqrt[3]{n}\)\(>\sqrt[3]{n}\) 两部分,
前面这一部分直接预处理,后面这一部分最多存在两个数,所以用莫队直接维护即可


代码

#include <cstdio>
#include <cctype>
#include <cmath>
#include <algorithm>
#define rr register
using namespace std; 
const int N=100011,mod=19260817,M=31621; struct rec{int l,r,rk;}q[N]; bool v[N];
int cnt[N<<1],inv[N<<1],f[N][3],s[170][N],Q,Cnt,ans[N],pos[N],bl,now=1,b[N<<1],n,m,prime[M];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans; 
}
inline void print(int ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
bool cmp(rec a,rec b){
    if (pos[a.l]^pos[b.l]) return a.l<b.l;
    return pos[a.l]&1?a.r<b.r:a.r>b.r;
}
inline void update(int x,int z){
	rr int f0=cnt[f[x][1]],f1=cnt[f[x][2]];
	for (rr int i=1;i<=f[x][0];++i)
	    if (f[x][i]) cnt[f[x][i]]+=z;
	rr int f2=cnt[f[x][1]],f3=cnt[f[x][2]];
	if (f[x][1]==f[x][2]) now=1ll*now*inv[f0]%mod*f2%mod;
	    else now=1ll*now*inv[f0]%mod*inv[f1]%mod*f2%mod*f3%mod;
}
signed main(){
	for (rr int i=2;i<=M;++i){
        if (!v[i]) prime[Cnt++]=i;
        for (rr int j=0;j<Cnt&&prime[j]*i<=M;++j){
        	v[i*prime[j]]=1;
        	if (i%prime[j]==0) break;
        }
    }
	n=iut(),Q=iut(),bl=sqrt(n),inv[0]=inv[1]=1;
	for (rr int i=1;i<=n;++i){
	    rr int x=iut();
		for (rr int j=0;j<170;++j)
		while (x%prime[j]==0)
			++s[j][i],x/=prime[j];
		for (rr int j=170;j<Cnt&&prime[j]*prime[j]<=x;++j)
			while (x%prime[j]==0) f[i][++f[i][0]]=prime[j],x/=prime[j];
		if (x>1) f[i][++f[i][0]]=x;
	}
	for (rr int i=1;i<=n;++i)
	for (rr int j=1;j<=f[i][0];++j) b[++m]=f[i][j];
	for (rr int i=2;i<=m+1;++i) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
	sort(b+1,b+1+m),m=unique(b+1,b+1+m)-b-1;
	for (rr int i=1;i<=n;++i)
	for (rr int j=1;j<=f[i][0];++j)
	    f[i][j]=lower_bound(b+1,b+1+m,f[i][j])-b;
	for (rr int i=0;i<=m;++i) cnt[i]=1;
	for (rr int i=0;i<170;++i)
	for (rr int j=2;j<=n;++j)
	    s[i][j]+=s[i][j-1];
	for (rr int i=1;i<=Q;++i)
		q[i]=(rec){iut(),iut(),i},ans[i]=1;
	for (rr int i=1;i<=n;++i) pos[i]=(i-1)/bl+1;
	sort(q+1,q+1+Q,cmp);
	rr int L=q[1].l,R=L-1;
	for (rr int i=1;i<=Q;++i){
		while (L>q[i].l) update(--L,1);
		while (R<q[i].r) update(++R,1);
		while (L<q[i].l) update(L++,-1);
		while (R>q[i].r) update(R--,-1);
		ans[q[i].rk]=now;
	}
	for (rr int i=1;i<=Q;++i)
		for (rr int j=0;j<170;++j)
		    ans[q[i].rk]=1ll*ans[q[i].rk]*(s[j][q[i].r]-s[j][q[i].l-1]+1)%mod;
	for (rr int i=1;i<=Q;++i) print(ans[i]),putchar(10);
	return 0;
}
posted @ 2021-10-19 16:38  lemondinosaur  阅读(29)  评论(0编辑  收藏  举报