看到好多大神留下的题解能看得懂,但是对于那个线性筛我表示我是蒟蒻我不会QAQ~
于是我决定来水一发(顺便留下这道权限题,什么时候有权限了再去交一(交易)发)
目前找了个过了的代码对拍发现并无错误&& 测试时间大致和那份程序差不多(应该能过吧~~)
题意:
n m
求 ∑ ∑ gcd(i,j)^k mod 1e9+7
i=1 j=1
min(n,m) n m
先枚举gcd(i,j).转化为求 ∑ d^k ∑ ∑ [gcd(i,j)==d]
d=1 i=1 j=1
思路:
n m
ans=∑ ∑ gcd(i,j)^k
i=1 j=1
n m
ans=∑ d^k(∑ ∑ [gcd(i,j)==d] )
d=1 i=1 j=1
min(n,m) min(n/d,m/d)
ans=∑ d^k ∑ u(t) *[n/dt]*[m/dt]
d=1 t=1
min(n,m) min(n/d,m/d)
ans=∑ d^k ∑ u(T/d) *[n/T]*[m/T]
d=1 T/d=1
min(n,m)
ans=∑ [n/T]*[m/T] ∑ u(T/d) *d^k
T=1 d|T
如果能线性筛出G(T)=∑ u(T/d) *d^k
d|T
因为G(T)中d^k和u(T/d)都是积性函数,且又是相乘,所以G(T)是积性函数
把G(T)展开(用所有的因子)
t t t
G(T)=π G(pi^xi) = π ∑ u(pi^xi/d) *d^k =π u(pi)*pi^(xi-1)^k + u(1)*pi^xi^k
i=1 i=1 d|pi^xi i=1
t t
=π -pi^[k*(xi-1)]+pi^[xi*k] =π pi^[k*(xi-1)](pi^k-1)
i=1 i=1
然后线性一波筛:
对于质数,我们求pi^k -1 .
不是质数的:(在枚举prime的时候)
如果是该质数的倍数,i*prime[j]就乘上prime[j]^k (一共有xi-1个这样的),因为pi^k-1已经计算过了。
如果不是倍数,就一定互质(prime[j]是质数),因为有连乘号,就乘起来。
附代码(跪求路过的有权限的帮我交一发,谢谢,while(1)orz;):
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
#include<iostream>
#include<cstring>
#include<cstdlib>
#define ll long long
using namespace std;
const int maxn=5000000+5;
const ll M=1e9+7;
/*
n,m,k;
n m
ans=∑ ∑ gcd(i,j)^k
i=1 j=1
n m
ans=∑ d^k(∑ ∑ [gcd(i,j)==d] )
d=1 i=1 j=1
min(n,m) min(n/d,m/d)
ans=∑ d^k ∑ u(t) *[n/dt]*[m/dt]
d=1 t=1
min(n,m) min(n/d,m/d)
ans=∑ d^k ∑ u(T/d) *[n/T]*[m/T]
d=1 T/d=1
min(n,m)
ans=∑ [n/T]*[m/T] ∑ u(T/d) *d^k
T=1 d|T
如果能线性筛出G(T)=∑ u(T/d) *d^k
d|T
因为G(T)中d^k和u(T/d)都是积性函数,且又是相乘,所以G(T)是积性函数
把G(T)展开(用所有的因子)
t t t
G(T)=π G(pi^xi) = π ∑ u(pi^xi/d) *d^k =π u(pi)*pi^(xi-1)^k + u(1)*pi^xi^k
i=1 i=1 d|pi^xi i=1
t t
=π -pi^[k*(xi-1)]+pi^[xi*k] =π pi^[k*(xi-1)](pi^k-1)
i=1 i=1
*/
ll n,m,k;
bool flag[maxn];
int prime[maxn];
int tot;
ll g[maxn];
ll sum[maxn];//g[i]的前缀和
ll qk(ll x,ll y)
{
ll res=1;
x%=M;
while(y)
{
if(y&1)res=res*x%M;
y>>=1;
x=x*x%M;
}
return res;
}
void init()
{
g[1]=1;
tot=0;
for(int i=2;i<=maxn;i++)
{
if(!flag[i])
{
prime[++tot]=i;
g[i]=qk((ll)i,k)-1;
}
for(int j=1;j<=tot&&i*prime[j]<=maxn;j++)
{
flag[i*prime[j]]=1;
if(i%prime[j]==0)
{
g[i*prime[j]]=g[i]*qk((ll)prime[j],k)%M;
break;
}
else g[i*prime[j]]=g[i]*g[prime[j]]%M;
}
}
for(int i=1;i<=maxn;i++)sum[i]=sum[i-1]+g[i];
}
int main()
{
int T;
scanf("%d%lld",&T,&k);
init();
while(T--)
{
scanf("%lld%lld",&n,&m);
// min(n,m)
//ans=∑ [n/T][m/T]G(T)
// T=1
ll ans=0;
ll h=min(n,m);
int pos;
for(int i=1;i<=h;i=pos+1)
{
pos=min(n/(n/i),m/(m/i));
ans+=(sum[pos]-sum[i-1])%M*(n/i)%M*(m/i);
ans%=M;
}
printf("%lld\n",ans);
}
return 0;
}