Description
对于正整数n,定义f(n)为n所含质因子的最大幂指数。例如f(1960)=f(2^3 * 5^1 * 7^2)=3, f(10007)=1, f(1)=0。
给定正整数a,b,求sigma(sigma(f(gcd(i,j)))) (i=1..a, j=1..b)。
Input
第一行一个数T,表示询问数。
接下来T行,每行两个数a,b,表示一个询问。
Output
对于每一个询问,输出一行一个非负整数作为回答。
Sample Input
4
7558588 9653114
6514903 4451211
7425644 1189442
6335198 4957
Sample Output
35793453939901
14225956593420
4332838845846
15400094813
HINT
【数据规模】
T<=10000
1<=a,b<=10^7
解题思路:
∑i=1n∑j=1mf(gcd(i,j)∑i=1n∑j=1mf(gcd(i,j)
=∑df(d)∑i=1n∑j=1m[gcd(i,j)=d]=∑df(d)∑i=1n∑j=1m[gcd(i,j)=d]
=∑df(d)∑i=1⌊nd⌋∑j=1⌊md⌋[gcd(i,j)=1]=∑df(d)∑i=1⌊nd⌋∑j=1⌊md⌋[gcd(i,j)=1]
=∑df(d)∑i=1⌊nd⌋∑j=1⌊md⌋∑p|i,p|jμ(p)=∑df(d)∑i=1⌊nd⌋∑j=1⌊md⌋∑p|i,p|jμ(p)
=∑df(d)∑pμ(p)∑i=1⌊npd⌋∑j=1⌊mpd⌋=∑df(d)∑pμ(p)∑i=1⌊npd⌋∑j=1⌊mpd⌋
=∑T∑i=1⌊nT⌋∑j=1⌊mT⌋∑d|Tμ(d)f(Td)=∑T∑i=1⌊nT⌋∑j=1⌊mT⌋∑d|Tμ(d)f(Td)
设g(x)=∑d|xμ(d)f(xd)g(x)=∑d|xμ(d)f(xd),考虑如何快速求g(x)g(x)
首先g(1)=0g(1)=0,否则设x=∏isptii,ti≤ti+1x=∏ispiti,ti≤ti+1,那么
g(x)=∑c1=0t1∑c2=0t2...∑cs=0tsμ(∏pcii)f(∏pti−cii)g(x)=∑c1=0t1∑c2=0t2...∑cs=0tsμ(∏pici)f(∏piti−ci)
g(x)=∑c1=01∑c2=01...∑cs=01μ(∏pci=0i)f(∏pti−cii)g(x)=∑c1=01∑c2=01...∑cs=01μ(∏pici=0)f(∏piti−ci)
若t1<tst1<ts,则
g(x)=∑c2=01...∑cs=01μ(∏pcii)f(pt11∏pti−cii)+g(x)=∑c2=01...∑cs=01μ(∏pici)f(p1t1∏piti−ci)+
∑c2=01...∑cs=01μ(p1∏pcii)f(pt1−11∏pti−cii)∑c2=01...∑cs=01μ(p1∏pici)f(p1t1−1∏piti−ci)
=∑c2=01...∑cs=01μ(∏pcii)f(pt11∏pti−cii)−=∑c2=01...∑cs=01μ(∏pici)f(p1t1∏piti−ci)−
∑c2=01...∑cs=01μ(∏pcii)f(pt1−11∏pti−cii)=0∑c2=01...∑cs=01μ(∏pici)f(p1t1−1∏piti−ci)=0
否则t1=t2=...=tst1=t2=...=ts
g(x)=∑∏ci≠1μ(∏pcii)t1+μ(∏pi)(t1−1)g(x)=∑∏ci≠1μ(∏pici)t1+μ(∏pi)(t1−1)
=∑c1=01∑c2=01...∑cs=01μ(∏pcii)t1−μ(∏pi)=∑c1=01∑c2=01...∑cs=01μ(∏pici)t1−μ(∏pi)
=∑i=0s(−1)iCis−μ(∏pi)=∑i=0s(−1)iCsi−μ(∏pi)
=−μ(∏pi)=(−1)s+1=−μ(∏pi)=(−1)s+1
这样就很好筛了,记录每个数最小质因数的幂数t(x)t(x)即除掉所有最小质因数后的数last(x)last(x)即可。
时间复杂度为O(n−Tn−−√)O(n−Tn)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int getint()
{
int i=0,f=1;char c;
for(c=getchar();(c!='-')&&(c<'0'||c>'9');c=getchar());
if(c=='-')c=getchar(),f=-1;
for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
const int N=10000005;
int pn,pri[N],t[N],last[N],g[N];
void sieve()
{
for(int i=2;i<N;i++)
{
if(!t[i])pri[++pn]=i,t[i]=last[i]=g[i]=1;
for(int j=1;j<=pn;j++)
{
ll k=i*pri[j];
if(k>=N)break;
if(i%pri[j]==0)
{
last[k]=last[i];
t[k]=t[i]+1;
if(last[k]==1)g[k]=1;
else g[k]=t[k]==t[last[k]]?-g[last[k]]:0;
break;
}
last[k]=i,t[k]=1,g[k]=(t[i]==1?-g[i]:0);
}
}
for(int i=2;i<N;i++)g[i]+=g[i-1];
}
ll F(int n,int m)
{
ll res=0;
if(n>m)swap(n,m);
for(int i=1,j;i<=n;i=j+1)
{
j=min(n/(n/i),m/(m/i));
res+=1ll*(n/i)*(m/i)*(g[j]-g[i-1]);
}
return res;
}
int main()
{
//freopen("lx.in","r",stdin);
sieve();
for(int T=getint();T;T--)
{
int n=getint(),m=getint();
printf("%lld\n",F(n,m));
}
return 0;
}