Description

给出A,B,考虑所有满足l<=a<=A,l<=b<=B,且不存在n>1使得n^2同时整除a和b的有序数

对(a,b),求其lcm(a,b)之和。答案模2^30。

Input

第一行一个整数T表示数据组数。接下来T行每行两个整数A,B表示一组数据。

T ≤ 2000,A,B ≤ 4 × 10^6

Output

对每组数据输出一行一个整数表示答案模2^30的值

Sample Input

5
2 2
4 6
3 4
5 1
23333 33333

Sample Output

7
148
48
15
451085813

Solution

\(f(i)\)表示\(i\)有无平方因子(有为\(0\),否则为\(1\)

那么题目的式子其实就是
\[ \sum_{i=1}^n\sum_{j=1}^mlcm(i,j)f(gcd(i,j)) \]
稍微用一下套路就可以化简到这步:

(设\(S(i)=\sum_{i=1}^ni\)
\[ \sum_{d=1}^n df(d)\sum_{k=1}^{\lfloor \frac{n}{d} \rfloor}\mu(k)k^2S(\lfloor \frac{n}{kd} \rfloor)S(\lfloor \frac{m}{kd} \rfloor) \]
\(T=kd\),换元可得
\[ \sum_{T=1}^nS(\lfloor \frac{n}{T} \rfloor)S(\lfloor \frac{m}{T} \rfloor)T\sum_{k|T}k\mu(k)f(\frac{T}{k}) \]
后面显然是个积性函数(两个积性函数的点积与另一个积性函数的狄利克雷卷积)

那么讨论一下来筛出来后面的就好了

\(g(i)=\sum_{k|i}k\mu(k)f(\frac{i}{k})\)

\(i=1\)时,\(g(i)=1\)

\(i\in prime\)时,\(g(i)=1-i\)

\(i\) 有平方质因子时,把平方质因子分离出来,手动展开一下就知道\(g(p^2)=-p,g(p^c)=0(c>2)\)。所以分离出来平方质因子然后分类讨论一下就好

复杂度\(O(n+T\sqrt{n})\)

因为取模是对\(2\)的整数次幂取模,所以直接在最后与\(2^{30}-1\)取与即可。

#include <bits/stdc++.h>
using namespace std;

namespace io {
char buf[1<<21], *p1 = buf, *p2 = buf;
inline char gc() {
    if(p1 != p2) return *p1++;
    p1 = buf;
    p2 = p1 + fread(buf, 1, 1 << 21, stdin);
    return p1 == p2 ? EOF : *p1++;
}
#define G gc

#ifndef ONLINE_JUDGE
#undef G
#define G getchar
#endif

template<class I>
inline void read(I &x) {
    x = 0; I f = 1; char c = G();
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = G(); }
    while(c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = G(); }
    x *= f;
}

template<class I>
inline void write(I x) {
    if(x == 0) {putchar('0'); return;}
    I tmp = x > 0 ? x : -x;
    if(x < 0) putchar('-');
    int cnt = 0;
    while(tmp > 0) {
        buf[cnt++] = tmp % 10 + '0';
        tmp /= 10;
    }
    while(cnt > 0) putchar(buf[--cnt]);
}

#define in(x) read(x)
#define outn(x) write(x), putchar('\n')
#define out(x) write(x), putchar(' ')

} using namespace io;

#define ll long long
const int N = 4000100;
const ll mod = (1 << 30);

ll g[N];
int n, m;
int cnt, p[N / 10], vis[N], tot[N], lev[N];

void init() {
    g[1] = 1;
    for(int i = 2; i < N; ++i) {
        if(!vis[i]) {
            p[++cnt] = i;
            g[i] = 1LL - i;
            lev[i] = i;
            tot[i] = 1;
        }
        for(int j = 1; j <= cnt && i * p[j] < N; ++j) {
            vis[i * p[j]] = 1;
            if(i % p[j] == 0) {
                lev[i * p[j]] = lev[i] * p[j];
                tot[i * p[j]] = tot[i] + 1;
                int tmp = i / lev[i];
                if(tot[i * p[j]] == 2) g[i * p[j]] = g[tmp] * (-p[j]);
                else g[i * p[j]] = 0;
                break;
            }
            g[i * p[j]] = g[i] * g[p[j]];
            lev[i * p[j]] = p[j];
            tot[i * p[j]] = 1;
        }
    }
    for(int i = 1; i < N; ++i) g[i] = (i * g[i] + g[i - 1]); 
}

ll c1(ll n) {
    return 1LL * n * (n + 1LL) / 2LL;
}

int main() {
    int T;
    read(T);
    init();
    while(T--) {
        ll ans = 0;
        read(n), read(m);
        if(n > m) swap(n, m);
        for(ll l = 1, r; l <= n; l = r + 1) {
            r = min(n / (n / l), m / (m / l));
            ans = (ans + c1(n / l) * c1(m / l) * (g[r] - g[l - 1])); 
        }
        outn(ans & (mod - 1));
    }
}