luoguP4902乘积题解
原题
题目简述:给定\(A,B\),让你求出下面这个式子的值:
规定:\(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\)的求法
设\(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\)的求法
我们还是设\(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;
}