Title

luoguP4902乘积题解

原题

题目简述:给定\(A,B\),让你求出下面这个式子的值:

\[\large \prod_{i=A}^B \prod_{j=1}^i (\frac i j )^{\lfloor \frac i j \rfloor} \bmod 19260817 \]

规定:\(d_x\)表示约数个数,\(T_x\)表示所有约数的乘积。

(以下省略模数)

\(h_x=\prod_{i=1}^x \prod_{j=1}^i (\frac i j )^{\lfloor \frac i j \rfloor}\)

那么\(Ans_{l,r}=\frac{h_r}{h_{l-1}}\)

接下来考虑如何求出\(h_i\)

\(h_x\)拆开,设\(P_x=\prod_{i=1}^x \prod_{j=1}^i i^{\lfloor \frac i j \rfloor}\),\(Q_x=\prod_{i=1}^x \prod_{j=1}^i (\frac 1 j )^{\lfloor \frac i j \rfloor}\),有\(h_x=P_x \times Q_x\)

\(P_x\)的求法

\[\large P_x=\prod_{i=1}^x i^{\sum_{j=1}^i \lfloor \frac i j \rfloor} \]

\(F(x)=\sum_{i=1}^x \lfloor \frac x i \rfloor\)

\(P_x=\prod_{i=1}^x i^{F(i)}\)

如果直接整除分块求\(F(x)\)是要带个根号的,无法接受,但是我们发现\(F(x+1)=F(x)+d_{x+1}\)

其实就是考虑\(x\)加一后对答案的贡献,我们发现只有\(i\)\(x+1\)的约数时才会影响答案。

然后通过\(x^{F(x)}\)的前缀积算出\(P(x)\)即可。

\(Q_x\)的求法

\[\large Q_x=\prod_{i=1}^x \prod_{j=1}^i (\frac 1 j )^{\lfloor \frac i j \rfloor} \]

\[\large \frac 1 {Q_x}=\prod_{i=1}^x \prod_{j=1}^i j^{\lfloor \frac i j \rfloor} \]

我们还是设\(G(x)=\prod_{i=1}^x i^{\lfloor \frac x i \rfloor}\),那么\(\frac 1 {Q_x}=\prod_{i=1}^x G(i)\)

求出\(G(x)\)我们还是要考虑\(x\)加一对答案的贡献,我们发现依然只有在\(i\)\(x+1\)的约数时才会对答案造成贡献,贡献值就是\(i\)本身,因此有\(G(x+1)=G(x) \times T_{x+1}\)

然后通过\(G(x)\)的前缀积算出\(Q(x)\)即可。

\(T_x\)的求法

对于一个数\(x\),根据唯一分解定理可知\(x=\prod_i P_i^{a_i}\)

我们考虑每一个质因子对约数之积的贡献,考虑它在所有的约数中出现了多少次。

对于\(P_i\),不包含它的约数个数为\(\frac {d_x} {a_i+1}\),我们在这些约数上面乘上\(1,2,3, \ldots,a_i\)\(P_i\),可以得出有\(\frac {d_x} {a_i+1} \times \frac {a_i \times (a_i+1)} 2\)\(P_i\),也就是\(\frac {a_i \times d_x} 2\)\(P_i\)

因此,\(T_x=\prod_i P_i^{\frac{a_i \times d_x} 2}=\prod_i (P_i^{a_i})^{\frac {d_x} 2}=(\prod_i P_i^{a_i})^{\frac {d_x} 2}=x^{\frac{d_x} 2}\)

Code:

#include<bits/stdc++.h>
using namespace std;
const int lim=1000000;
const int mod=19260817;
int d[lim+5],num[lim+5],P[lim+5],prim=0,vis[lim+5];
int f[lim+5],sumi[lim+5],sumj[lim+5],g[lim+5],T[lim+5];
int power(int x,long long y)
{
	int ans=1,last=x;
	while(y)
	{
		if(y&1)
			ans=1ll*ans*last%mod;
		last=1ll*last*last%mod;
		y>>=1;
	}
	return ans;
}
int Sqrt(int x,int y)
{
	if(y%2==0)
		return power(x,y/2);
	else
	{
		int p=sqrt(x);
		if(p*p<x)
			p++;
		return power(p,y);
	} 
}
void pre()
{
	d[1]=T[1]=1;
	for(int i=2;i<=lim;i++)
	{
		if(!vis[i])
		{
			vis[i]=num[i]=1;
			d[i]=2;T[i]=i;
			P[++prim]=i;
		} 
		for(int j=1;j<=prim&&i*P[j]<=lim;j++)
		{
			vis[i*P[j]]=1;
			if(i%P[j]==0)
			{
				num[i*P[j]]=num[i]+1;
				d[i*P[j]]=d[i]/(num[i]+1)*(num[i]+2);
				break;
			}
			d[i*P[j]]=d[i]*2;
			num[i*P[j]]=1;
		}
	}//线性筛求约数个数 
	f[1]=g[1]=1;
	for(int i=1;i<=lim;i++)
		T[i]=Sqrt(i,d[i]);//求出约数之积 
	for(int i=2;i<=lim;i++)
		f[i]=f[i-1]+d[i],g[i]=1ll*g[i-1]*power(T[i],mod-2)%mod;//此处求出f[i]和g[i]的倒数 
	for(int i=1;i<=lim;i++)
		f[i]=power(i,f[i]);
	sumi[0]=sumj[0]=1;
	for(int i=1;i<=lim;i++)
		sumi[i]=1ll*sumi[i-1]*f[i]%mod;//前缀积 
	for(int i=1;i<=lim;i++)
		sumj[i]=1ll*sumj[i-1]*g[i]%mod;//前缀积 
}
int main()
{
	pre();
	int t,l,r;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&l,&r);
		printf("%d\n",1ll*sumi[r]*power(sumi[l-1],mod-2)%mod*sumj[r]%mod*power(sumj[l-1],mod-2)%mod); 
	}
	
	return 0;
}
posted @ 2021-12-16 12:02  五百年前  阅读(59)  评论(0编辑  收藏  举报