按照套路化到最后是:
问题就在于怎么求
![]()
![]()
法 :
对
做唯一分解,则
然后用数组记录
含有的质数个数,是否为以上两种形式之一,即可递推。
法 :
考虑在线性筛的时候处理。
筛合数时,
,
若
的唯一分解中每一项的幂次都为
,则只有
时
,
.
若
的唯一分解中每一项的幂次不都为
,则有一项的幂次不小于
,则
故
筛合数时,
,
由法
,
法 代码:
#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; }