题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4407
题目分析:又是一道老年人数论题。
不妨令
n≤m
n
≤
m
。经过一番推导倒,可以得到这个:
令 G(i)=ik G ( i ) = i k ,它是个完全积性函数,可以通过预处理所有质数的 G G 然后线性筛得到。求质数的值可以用快速幂。由于质数个数是 nln(n) n ln ( n ) 级别的,所以这部分时间为 O(nlog(k)ln(n)) O ( n log ( k ) ln ( n ) ) 。又因为 n,k n , k 大小相近,可以认为接近 O(n) O ( n ) 。
第二个 ∑ ∑ 后面的式子记为 F(D) F ( D ) ,它是 G G 卷,所以也是积性函数。令 p p 为质数,则可以预处理全部,然后用线性筛得到所有 F F 值。根据定义显然有。然后对于每个询问下底函数分块,总时间为 O(n+Tn−−√) O ( n + T n ) 。
一开始 G G <script type="math/tex" id="MathJax-Element-2161">G</script>数组乘起来的时候忘了取模,WA了一次。
CODE:
#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxn=5000010;
const long long M=1000000007;
typedef long long LL;
int p[maxn];
LL G[maxn];
LL F[maxn];
bool vis[maxn];
int prime[maxn];
int cur=0;
int t,n,m,k;
LL Fast_power(LL x,LL y)
{
if (!y) return 1LL;
LL temp=Fast_power(x,y>>1);
temp=temp*temp%M;
if (y&1) temp=temp*x%M;
return temp;
}
void Linear_shaker()
{
G[1]=1;
for (int i=2; i<maxn; i++)
{
if (!vis[i]) G[i]=Fast_power(i,k),p[i]=i,prime[++cur]=i;
for (int j=1; j<=cur && i*prime[j]<maxn; j++)
{
int K=i*prime[j];
vis[K]=true;
G[K]=G[i]*G[ prime[j] ]%M;
if (i%prime[j]) p[K]=prime[j];
else
{
p[K]=p[i]*prime[j];
break;
}
}
}
F[1]=1LL;
for (int i=1; i<=cur; i++)
{
LL x=prime[i],last=1;
while (x<(long long)maxn)
{
F[x]=(G[x]-G[last]+M)%M;
last=x;
x*=(long long)prime[i];
}
}
for (int i=2; i<maxn; i++)
if (p[i]<i) F[i]=F[ p[i] ]*F[ i/p[i] ]%M;
for (int i=1; i<maxn; i++) F[i]=(F[i-1]+F[i])%M;
}
int main()
{
freopen("4407.in","r",stdin);
freopen("4407.out","w",stdout);
scanf("%d%d",&t,&k);
Linear_shaker();
while (t--)
{
scanf("%d%d",&n,&m);
if (n>m) swap(n,m);
LL ans=0;
int last;
for (int i=1; i<=n; i=last+1)
{
last=min( n/(n/i) , m/(m/i) );
ans=(ans+ (long long)(n/i)*(m/i)%M*( F[last]-F[i-1]+M )%M )%M;
}
printf("%I64d\n",ans);
}
return 0;
}