于神之怒加强版 解题报告 于神之怒加强版
题目描述
给定(n,m,k),计算
[sum_{i=1}^n sum_{j=1}^m mathrm{gcd}(i,j)^k
]
对(1000000007)取模的结果
说明
(Tle 2000,1le N,M,Kle 5000000)
注意(k)不是每次都给的...
可以推出式子
[sum_{T=1}^{min(n,m)}lfloorfrac{n}{T}
floorlfloorfrac{m}{T}
floorsum_{ab=T}a^kmu(b)
]
然后预处理一下右边,发现右边是(f=Id^k*mu),所以是积性的
因为(Id^k)是完全积性函数,所以可以(O(n))预处理
然后又有(f(p^c)=(p^c)^k-(p^{c-1})^k),(p)是质数,就可以筛了
Code:
#include <cstdio>
#include <algorithm>
using std::min;
const int N=5e6+1;
const int mod=1000000007;
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
#define mul(a,b) (1ll*(a)*(b)%mod)
int qp(int d,int k){int f=1;while(k){if(k&1)f=mul(f,d);d=mul(d,d),k>>=1;}return f;}
int Id[N],b[N],f[N],pri[N],ispri[N],k,cnt;
void init()
{
Id[1]=b[1]=f[1]=1;
for(int i=2;i<N;i++)
{
if(!ispri[i])
{
Id[i]=qp(i,k);
f[i]=Id[i]-1;
b[i]=i;
pri[++cnt]=i;
}
for(int j=1;j<=cnt&&i*pri[j]<N;j++)
{
int x=pri[j]*i;
ispri[x]=1;
Id[x]=mul(Id[i],Id[pri[j]]);
if(i%pri[j])
{
b[x]=pri[j];
f[x]=mul(f[i],f[pri[j]]);
}
else
{
b[x]=mul(b[i],pri[j]);
if(b[i]==i) f[x]=add(Id[x],mod-Id[i]);
else f[x]=mul(f[i/b[i]],f[b[x]]);
break;
}
}
}
for(int i=2;i<N;i++) f[i]=add(f[i],f[i-1]);
}
int main()
{
int T,n,m;scanf("%d%d",&T,&k);
init();
while(T--)
{
scanf("%d%d",&n,&m);
int ans=0;
if(n>m) std::swap(n,m);
for(int l=1,r;l<=n;l=r+1)
{
r=min(n/(n/l),m/(m/l));
ans=add(ans,mul(n/l,mul(m/l,add(f[r],mod-f[l-1]))));
}
printf("%d
",ans);
}
return 0;
}
2019.3.17