#### **项目编号:bzoj-3309**

项目等级: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)) $$
又有$\epsilon = \mu * 1$,故
$$ 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 $$
设$T = d g$,则
$$ 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) $$
设$g(T) = \sum _ {d | T} f(d) \mu(\frac T d) = \sum _ {d | T} f(\frac T d) \mu(d)$。

可证明\(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;
}