@xiaoziyao
2020-05-23T04:59:41.000000Z
字数 3337
阅读 1600
解题报告
备注:为质数集,为自然数集。
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;}
