项目等级:Safe
项目描述:
特殊收容措施:
以下用\((x, y)\)表示\(gcd(x, y)\)。
$$ ans = \sum _ {i = 1} ^ {a} \sum _ {j = 1} ^ {b} f((i, j)) = \sum _ {g = 1} ^ {min(a, b)} f(g) \sum _ {i = 1} ^ {\lfloor {\frac a g} \rfloor} \sum _ {j = 1} ^ {\lfloor {\frac b g} \rfloor} \epsilon((i, j)) $$ |
$$ ans = \sum _ {g = 1} ^ {min(a, b)} f(g) \sum _ {i = 1} ^ {\lfloor {\frac a g} \rfloor} \sum _ {j = 1} ^ {\lfloor {\frac b g} \rfloor} \sum _ {d | i, d | j} \mu(d) = \sum _ {g = 1} ^ {min(a, b)} f(g) \sum _ {d = 1} ^ {min(\lfloor {\frac a g} \rfloor, \lfloor {\frac b g} \rfloor)} \mu(d) \lfloor {\frac a {d g}} \rfloor \lfloor {\frac b {d g}} \rfloor $$ |
$$ ans = \sum _ {T = 1} ^ {min(a, b)} \lfloor {\frac a T} \rfloor \lfloor {\frac b T} \rfloor \sum _ {g | T} f(g) \mu(\frac T g) $$ |
可证明\(h(T) = \lfloor {\frac a T} \rfloor \lfloor {\frac b T} \rfloor\)的取值只有\(\sqrt[]{min(a,b)}\)段。
这样对于\(h(T)\)取值相同的\(T\),其总贡献为\(h(T) \sum g(T)\),于是只需要线性筛出\(g\)函数计算前缀和即可。
以下考虑\(g(T)\)的性质。
因为当且仅当\(p ^ 2 \not| d\)即\(\mu(d) \not= 0\)时,\(f(\frac T d)\)对\(g(T)\)有贡献。
设\(T = \prod _ {i = 1} ^ {k} p _ i ^ {q _ i}, r = max \{q _ i\}\),
集合\(A = \{q _ i = r\}, B = \complement _ {Q} ^ {A}\)。
若\({\exists}i < j\)使得\(q _ i \not= q _ j\)时:
一旦确定了\(A\)中d的质因数选取方案,\(f(\frac T d)\)也随即确定。
此时所有集合\(B\)中d的质因数选取方案\(\sum \mu(d)=0\),故此情况对\(g(T)\)贡献为0。
\(\forall i, j\)使得\(q _ i = q _ j\)时:
当且仅当\(d = \prod _ {i = 1} ^ {k} p _ i\)时,\(f(d) = r\),否则\(f(d) = r - 1\)。
故\(g(T) = (r \sum \mu(d)) + (-1) ^ {k + 1}\)。
又\(\sum \mu(d)=0\),故\(g(T) = (-1) ^ {k + 1}\)。
由此,可根据以上性质筛出g。
附录:
#include <bits/stdc++.h>
#define range(i,c,o) for(register int i=(c);i<(o);++i)
using namespace std;
// QUICK_IO BEGIN HERE
#ifdef __WIN32
#define getC getchar
#define putLL(x,c) printf("%I64d%c",x,c)
#else
#define getC getchar_unlocked
#define putLL(x,c) printf("%lld%c",x,c)
#endif
inline unsigned getU()
{
char c; unsigned r=0;
while(!isdigit(c=getC()));
for(;isdigit(c);c=getC())
{
r=(r<<3)+(r<<1)+c-'0';
}
return r;
}
// QUICK_IO END HERE
static const int MAXN=10000000;
bool flag[MAXN+5]; int pr[MAXN>>2];
int las[MAXN+5]; // for x=y*cur_p^cur_q, las[x]=y
int cnt[MAXN+5]; // for x=y*cur_p^cur_q, cnt[x]=cur_q
int g[MAXN+5]; // g(x)=sigma(f(d)*mu(x/d),d|x)
inline long long solve(const int&x,const int&y)
{
long long ret=0;
for(int i=1,j;i<=min(x,y);i=j+1)
{
j=min(x/(x/i),y/(y/i));
ret+=1LL*(g[j]-g[i-1])*(x/i)*(y/i);
}
return ret;
}
int main()
{
int tot=0;
range(i,2,MAXN+1)
{
if(!flag[i]) pr[tot++]=i,las[i]=cnt[i]=g[i]=1;
range(j,0,tot)
{
int x=i*pr[j];
if(x>MAXN) break;
flag[x]=1;
if(i%pr[j]==0)
{
las[x]=las[i],cnt[x]=cnt[i]+1,
g[x]=(las[x]==1?1:-g[las[x]]*(cnt[las[x]]==cnt[x]));
break;
}
las[x]=i,cnt[x]=1,g[x]=-g[i]*(cnt[i]==1);
}
}
range(i,1,MAXN+1) g[i]+=g[i-1];
for(int T=getU();T--;)
{
int x=getU(),y=getU(); putLL(solve(x,y),'\n');
}
return 0;
}