题面:https://www.luogu.com.cn/problem/P5071

 

 

 

 

题解

(๑•̀ㅂ•́)و✧题面好评(๑•̀ㅂ•́)و✧

٩(๑>◡<๑)۶人生第一道Ynoi٩(๑>◡<๑)۶

先把所有数用PR分解质因数

用莫队的话,思路就比较简单了,直接统计所有质因子的个数,就可以算出来乘积的约数个数

(当然,要先离散化质因子,预处理逆元)

但是所有数质因子个数平均为log级别的

莫队一次移动端点的复杂度就会变为log

总复杂度为O(n*sqrt(m)*logN)

过不了。。。

因为我们莫队的查询总复杂度为O(m)

但是修改复杂度为O(n*sqrt(m)*logN)

所以要想办法把它们两个平均一下

于是我们考虑按质因子的大小来分成两部分来计算答案,质因子小于500只有95个,可以先预处理出前缀和,O(95)查询

剩下的质因子大于500就可以用莫队直接加,可以发现这样的质因子最多只有3个,O(3)修改

总复杂度就为O(n*sqrt(m)*3+m*95)

理论上可以过了

 

(接下来是鬼畜卡常时间)

然而还是T了。。。

写了个数据生成器

发现是分解质因数的时候太慢了,PR被卡了(早知道就不作死写PR了。。。),Pollard_Rho怎么这么不争气啊

想了一下,好像可以筛出1e7的质数,然后试除法,途中用Miller_Robin来判断,1e7以内的数就可以直接判断了

如果中途x已经为质数了就直接退出

然后WA5个T5个。。。

又WA又T真自闭

突然想起来莫队有一个分奇偶排序的优化

加了之后就全部WA了

开始写对拍

后来发现是自己分解质因数的时候没有把所有的质因子统计完

改了之后就A了

 

AC代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int gi()
{
	char c;int num=0,flg=1;
	while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
	while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
	return num*flg;
}
#define N 100005
#define M 500
const int mod=19260817;
int prime[1400005],tot;
int inv[500005];
bool vis[20000005];
void shai()
{
	vis[1]=1;
	int i,j;
	for(i=2;i<=20000000;i++){
		if(!vis[i])prime[++tot]=i;
		for(j=1;j<=tot;j++){
			int tmp=i*prime[j];
			if(tmp>20000000)break;
			vis[tmp]=1;
			if(i%prime[j]==0)break;
		}
	}
	inv[1]=inv[0]=1;
	for(i=2;i<=500000;i++)
		inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
}

int pr[105],pcnt;
int a[N][5],cnt[N],hh[5*N],hcnt;
int sum[100][N];
inline int ksm(int x,int y,int p)
{
	int ret=1;
	while(y){
		if(y&1)ret=1ll*x*ret%p;
		y>>=1;x=1ll*x*x%p;
	}
	return ret;
}
int gcd(int x,int y){return !y?x:gcd(y,x%y);}
int bas[6]={3,7,37,79,97,19260817};
inline bool mler(int n)
{
	if(n<=20000000)return vis[n]^1;
	int r=n-1,t=0;
	while(!(r&1))r>>=1,t++;
	for(int i=0;i<6;i++){
		if(n==bas[i])return 1;
		int now,pre=ksm(bas[i],r,n);
		for(int k=0;k<t;swap(now,pre),k++)
			if((now=1ll*pre*pre%n)==1&&pre!=1&&pre!=n-1)
				return 0;
		if(pre!=1)return 0;
	}
	return 1;
}
/*inline int ab(int x){return x<0?-x:x;}
int rho(int n,int c)
{
	int i=1,j=0,x=rand()%(n-1)+1,y=x;
	int d=1,tmp=1;
	while(d==1){
		x=(1ll*x*x+c)%mod;
		tmp=1ll*tmp*ab(y-x)%mod;
		if(++j==i)i<<=1,y=x,d=gcd(tmp,n);
		if(!(j&127))d=gcd(tmp,n);
	}
	return d==n?rho(n,c+1):d;
}

void plar(int n)
{
	if(n==1)return;
	if(mler(n)){pr[++pcnt]=n;return;}
	int d=rho(n,3);
	plar(d);plar(n/d);
}*/
#define D 366
int tong[5*N],ans[N];
struct node{
	int l,r,id;
}q[N];
inline bool cmp(const node &x,const node &y){int t=(x.l)/D;return t<(y.l/D)||(t==(y.l/D)&&(((t&1)&&x.r<y.r)||(!(t&1)&&x.r>y.r)));}
inline int query(int l,int r)
{
	int ret=1;
	for(int i=1;i<=95;i++)
		ret=1ll*ret*(sum[i][r]-sum[i][l-1]+1)%mod;
	return ret;
}
//#include<ctime>
//double c1;
int main()
{
	//c1=clock();
	//freopen("1.in","r",stdin);
	
	srand(0);shai();
	int n,i,j,m,x,l,r,mul,tmp;
	n=gi();m=gi();
	for(i=1;i<=n;i++){
		x=gi();//printf("%d\n",i);
		bool flg;
		if(x>500&&mler(x)){
			a[i][++cnt[i]]=x;
			hh[++hcnt]=x;
			//printf("%d\n",x);
			continue;
		}
		for(j=1;j<=95&&x>1;j++){
			flg=0;
			while(x%prime[j]==0){
				sum[j][i]++;
				x/=prime[j];
				//printf("%d ",prime[j]);
				flg=1;
			}
		}
		if(x>500&&mler(x)){
			a[i][++cnt[i]]=x;
			hh[++hcnt]=x;
			//printf("%d\n",x);
			continue;
		}
		for(j=96;1ll*prime[j]*prime[j]<=x&&x>1;j++){
			flg=0;
			while(x%prime[j]==0){
				a[i][++cnt[i]]=prime[j];
				hh[++hcnt]=prime[j];
				//printf("%d ",prime[j]);
				x/=prime[j];
				flg=1;
			}
			if(flg&&mler(x))break;
		}
		if(x>500){
			a[i][++cnt[i]]=x;
			hh[++hcnt]=x;
		}
		//printf("%d\n",x);
		/*pcnt=0;plar(x);
		for(j=1;j<=pcnt;j++){
			a[i][++cnt[i]]=pr[j];
			hh[++hcnt]=pr[j];
			//printf("%d ",pr[j]);
		}*/
	}
	sort(hh+1,hh+hcnt+1);
	hcnt=unique(hh+1,hh+hcnt+1)-hh-1;
	for(i=1;i<=n;i++)
		for(j=1;j<=cnt[i];j++)
			a[i][j]=lower_bound(hh+1,hh+hcnt+1,a[i][j])-hh;
	for(i=1;i<=95;i++)
		for(j=1;j<=n;j++){
			sum[i][j]+=sum[i][j-1];
			if(sum[i][j]>=mod)sum[i][j]-=mod;
		}
	for(i=1;i<=m;i++){q[i].l=gi();q[i].r=gi();q[i].id=i;if(q[i].l>q[i].r)swap(q[i].l,q[i].r);}
	sort(q+1,q+m+1,cmp);
	
	mul=1;l=1;r=0;
	
	//printf("%.3fs\n",(clock()-c1)/1000);
	//freopen("1.out","w",stdout);
	for(i=1;i<=m;i++){
		while(l>q[i].l){
			l--;
			for(j=1;j<=cnt[l];j++){
				tmp=(++tong[a[l][j]]);
				mul=1ll*mul*inv[tmp]%mod*(tmp+1)%mod;
			}
		}
		while(r<q[i].r){
			r++;
			for(j=1;j<=cnt[r];j++){
				tmp=(++tong[a[r][j]]);
				mul=1ll*mul*inv[tmp]%mod*(tmp+1)%mod;
			}
		}
		while(l<q[i].l){
			for(j=1;j<=cnt[l];j++){
				tmp=(--tong[a[l][j]]);
				mul=1ll*mul*inv[tmp+2]%mod*(tmp+1)%mod;
			}
			l++;
		}
		while(r>q[i].r){
			for(j=1;j<=cnt[r];j++){
				tmp=(--tong[a[r][j]]);
				mul=1ll*mul*inv[tmp+2]%mod*(tmp+1)%mod;
			}
			r--;
		}
		ans[q[i].id]=1ll*mul*query(l,r)%mod;
	}
	for(i=1;i<=m;i++)
		printf("%d\n",ans[i]);
	//freopen("CON","w",stdout);
	//printf("%.3fs\n",(clock()-c1)/1000);
}

 

应该是我的PR有问题,不然PR会更块的吧。。。