@xiaoziyao
2020-05-23T12:59:41.000000Z
字数 3337
阅读 1154
解题报告
备注:为质数集,为自然数集。
P4449 于神之怒加强版解题报告:
题意:给定与,后有组数据给定和,求。数据范围:,。
我们可以先给原式变换一下形式(以下默认):
首先套路性地枚举:(中括号内的是一个有点像的东西)
可以发现造成贡献的都是的,那么和肯定是的倍数,我们就将和缩小倍:
然后莫比乌斯反演():
由于是的因数,因此一定是和的公因数,仿照上面,我们将和缩小倍(顺便改变一下运算顺序):
稍微做一下变形:
然后我们可以设(这样我们可以把的枚举变为枚举的因数),然后可以得到:
设,则原式化为:
然后我们用整除分块可以做到的时间,于是我们的目标转移到如何线性筛预处理函数:
由两个积性函数(与)
的狄利克雷卷积也是一个积性函数,我们可以构造的标准分解得到,于是我们转而计算一个质数的幂次方。
由莫比乌斯函数的性质(如果一个数是一个完全平方数的倍数,那么,这是莫比乌斯函数的定义)可得,当,:
因此很显然有:
然后我们考虑求,发现
最后,我们讨论一下如何线性筛(求,,):
当时,取中的幂次,则由的积性有
由上文求出的得再用的积性合并得:
当时,直接由的积性可得
综上所述
故线性筛+数论分块即可。
代码:
#include<stdio.h>
const long long maxn=5000005,mod=1000000007;
long long i,j,k,m,n,T,cnt,l,r,ans;
long long a[maxn],p[maxn],f[maxn],pf[maxn];
inline long long min(long long a,long long b){
return a<b? a:b;
}
long long ksm(long long a,long long b){
long long res=1;
while(b){
if(b&1)
res=(res*a)%mod;
a=(a*a)%mod,b>>=1;
}
return res;
}
int main(){
scanf("%lld%lld",&T,&k);
p[1]=f[1]=1;
for(i=2;i<maxn;i++){
if(p[i]==0)
a[++cnt]=i,f[i]=(ksm(i,k)-1+mod)%mod;
for(j=1;j<=cnt;j++){
if(i*a[j]>=maxn)
break;
p[i*a[j]]=1;
if(i%a[j]==0){
f[i*a[j]]=f[i]*ksm(a[j],k)%mod;
break;
}
f[i*a[j]]=f[i]*f[a[j]]%mod;
}
}
for(i=1;i<maxn;i++)
pf[i]=pf[i-1]+f[i];
while(T--){
scanf("%lld%lld",&n,&m);
l=1,ans=0;
while(l<=min(n,m)){
r=min(n/(n/l),m/(m/l));
ans=((ans+(pf[r]-pf[l-1]+mod)%mod*(n/l)%mod*(m/l)%mod)%mod+mod)%mod;
l=r+1;
}
printf("%lld\n",ans);
}
return 0;
}