题解 P4449 【于神之怒加强版】
求
多组询问,但是每次的
先是套路
我们要求的就是
交换一下枚举顺序
我们设
这显然是一个积性函数
考虑一下如何线筛这个积性函数
如果
发现这个形式很像欧拉函数,可以尝试搞一下
发现从
可以直接不用考虑这个约数
于是
因为新多出来的那一个约数并不需要考虑,因为其
所以
所以
发现这个跟欧拉函数好像啊,我们完全可以按照线性筛欧拉函数的方式来线筛
所以线筛之后求一个前缀和之后分块就好了
#include<iostream>
#include<cstring>
#include<cstdio>
#define re register
#define maxn 5000005
#define LL long long
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
const LL mod=1000000007;
inline int read()
{
char c=getchar();
int x=0;
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9')
x=(x<<3)+(x<<1)+c-48,c=getchar();
return x;
}
int p[maxn>>1],f[maxn],T,n,m;
LL pre[maxn];
int N[2005],M[2005];
inline LL quick(LL a,LL b)
{
LL S=1;
while(b){if(b&1) S=S*a%mod;b>>=1;a=a*a%mod;}
return S;
}
LL K;
int main()
{
T=read(),K=read();
for(re int i=1;i<=T;i++) N[i]=read(),M[i]=read();
for(re int i=1;i<=T;i++) if(N[i]>M[i]) std::swap(N[i],M[i]);
for(re int i=1;i<=T;i++) n=max(n,M[i]);
f[1]=1,pre[1]=1;
for(re int i=2;i<=n;i++)
{
if(!f[i]) p[++p[0]]=i,pre[i]=quick(i,K)-1;
for(re int j=1;j<=p[0]&&p[j]*i<=n;j++)
{
f[p[j]*i]=1;
if(i%p[j]==0)
{
pre[p[j]*i]=pre[i]*(pre[p[j]]+1)%mod;
break;
}
pre[p[j]*i]=pre[p[j]]*pre[i]%mod;
}
}
for(re int i=1;i<=n;i++) pre[i]=(pre[i]+pre[i-1])%mod;
for(re int t=1;t<=T;t++)
{
n=N[t],m=M[t];
LL ans=0;
for(re LL l=1,r;l<=n;l=r+1)
{
r=min(n/(n/l),m/(m/l));
ans=(ans+(n/l)*(m/l)%mod*(pre[r]-pre[l-1]+mod)%mod)%mod;
}
printf("%lld\n",ans);
}
return 0;
}