题面戳我
Description
给下N,M,K.求
\[\sum_{i=1}^{n}\sum_{j=1}^{m}\gcd(i,j)^k\quad(mod\quad1e9+7)\]
Input
输入有多组数据,输入数据的第一行两个正整数T,K,代表有T组数据,K的意义如上所示,下面第二行到第T+1行,每行为两个正整数N,M,其意义如上式所示。
Output
如题
Sample Input
1 2
3 3
Sample Output
20
HINT
1<=N,M,K<=5000000,1<=T<=2000
sol
首先单组数据\(O(n)\)的都会噻,就不讲了。(就是内外数论分块\(O(\sqrt n*\sqrt n)=O(n)\)的那种)
这种方法化到最后的答案式应该是
\[ans=\sum_{d=1}^{n}d^k\sum_{i=1}^{n/d}\mu(i)\lfloor\frac n{di}\rfloor\lfloor\frac m{di}\rfloor\]
我们现在令\(T=di\),然后考虑分别计算每一个\(\lfloor\frac nT\rfloor\lfloor\frac mT\rfloor\)对答案的贡献
\[ans=\sum_{T=1}^{n}\lfloor\frac nT\rfloor\lfloor\frac mT\rfloor*\sum_{d|T}d^k\mu(\frac Td)\]
(手玩一下发现就是这样的)
前面那一坨显然还是\(O(\sqrt)\)分块,后面那一坨发现是一个狄利克雷卷积的形式,就是说它还是一个积性函数。线性筛出来后维护一个前缀和即可。
code
我不会说我因为ans没有清零WA了两次的
#include<cstdio>
#include<algorithm>
using namespace std;
#define ll long long
const ll N = 5000005;
const ll maxn = 5000000;
const ll mod = 1e9 + 7;
ll gi()
{
ll x=0,w=1;char ch=getchar();
while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if (ch=='-') w=0,ch=getchar();
while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return w?x:-x;
}
ll fastpow(ll a,ll b)
{
ll s=1;
while (b)
{
if (b&1) s=s*a%mod;
a=a*a%mod;b>>=1;
}
return s;
}
ll t,k,n,m,pri[N],tot,zhi[N],low[N],h[N],ans;
void Mobius()
{
zhi[1]=h[1]=low[1]=1;
for (ll i=2;i<=maxn;i++)
{
if (!zhi[i]) low[i]=pri[++tot]=i,h[i]=(fastpow(i,k)-1+mod)%mod;
for (ll j=1;j<=tot&&i*pri[j]<=maxn;j++)
{
zhi[i*pri[j]]=1;
if (i%pri[j]==0)
{
low[i*pri[j]]=low[i]*pri[j];
if (low[i]==i)
h[i*pri[j]]=h[i]*(h[pri[j]]+1)%mod;
else
h[i*pri[j]]=h[i/low[i]]*h[low[i]*pri[j]]%mod;
break;
}
low[i*pri[j]]=pri[j];
h[i*pri[j]]=h[i]*h[pri[j]]%mod;
}
}
for (ll i=1;i<=maxn;i++) h[i]=(h[i]+h[i-1])%mod;
}
int main()
{
t=gi();k=gi();
Mobius();
while (t--)
{
n=gi();m=gi();ans=0;
if (n>m) swap(n,m);
ll i=1;
while (i<=n)
{
ll j=min(n/(n/i),m/(m/i));
ans=(ans+(h[j]-h[i-1]+mod)%mod*((n/i)*(m/i)%mod)%mod)%mod;
i=j+1;
}
printf("%lld\n",ans);
}
return 0;
}