按照套路化到最后是:
问题就在于怎么求
![]()
![]()
法 :
对
做唯一分解,则
然后用数组记录
含有的质数个数,是否为以上两种形式之一,即可递推。
法 :
考虑在线性筛的时候处理。
筛合数时,
,
若
的唯一分解中每一项的幂次都为
,则只有
时
,
.
若
的唯一分解中每一项的幂次不都为
,则有一项的幂次不小于
,则
故
筛合数时,
,
由法
,
法 代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define ll long long int
#define rep(i,a,b) for(int i = (a); i <= (b); i ++)
#define dwn(i,a,b) for(int i = (a); i >= (b); i --)
using namespace std;
const int maxn = 1e7 + 100;
int cut, p[maxn], isp[maxn], can1[maxn], can2[maxn];
ll cntp[maxn], g[maxn];
void gt(int n)
{
if(can1[n])
g[n] = cntp[n] * ((cntp[n] - 1) % 2 == 1? -1LL: 1LL);
if(can2[n])
g[n] = (cntp[n] % 2 == 1? -1LL: 1LL);
}
void shai()
{
int n = 1e7;
g[1] = 0;
cntp[1] = 0;
can1[1] = 1;
can2[1] = 0;
rep(i,2,n)
{
if(!isp[i])
{
p[ ++ cut] = i;
cntp[i] = 1;
can1[i] = 1;
can2[i] = 0;
gt(i);
}
for(int j = 1; j <= cut && i * p[j] <= n; j ++)
{
isp[i * p[j]] = 1;
if(i % p[j] == 0)
{
cntp[i * p[j]] = cntp[i];
can1[i * p[j]] = 0;
if(can1[i] == 1)
can2[i * p[j]] = 1;
else
can2[i * p[j]] = 0;
gt(i * p[j]);
break;
}
else
{
cntp[i * p[j]] = cntp[i] + 1;
can1[i * p[j]] = can1[i];
can2[i * p[j]] = can2[i];
gt(i * p[j]);
}
}
}
rep(i, 2, n) g[i] = g[i] + g[i - 1];
}
int main()
{
shai();
int T;
cin >> T;
rep(ci,1,T)
{
int n, m;
cin >> n >> m;
ll Ans = 0;
for(int l = 1; l <= n && l <= m;)
{
int r = min(n / (n / l), m / (m / l));
Ans += (ll)(n / l) * (ll)(m / l) * (g[r] - g[l - 1]);
l = r + 1;
}
cout << Ans << endl;
}
return 0;
} 
京公网安备 11010502036488号