Inversion of Mobius

Keywords: C++

Write in front

This is the first time konjaku has written such a long blog

\(gyh\ nb\),\(\text{OI-Wiki}\ nb\)

If you think it's OK to write, please click support \ (qwq \)

Prior knowledge

Product function,Dirichlet convolution,Number theory is divided into parts (go to gyh for this article, I can't talk about it well) (make up slowly when you have time)

Mobius function

Definition

The Mobius function \ (\ mu(n) \) is defined as:

\[\mu(n)=\left\{ \begin{aligned} 1, & n=1 \\ (-1)^{s}, & n=p_1p_2… P ﹣ s (s is the number of quality factors with different nature of n) \ \ 0, & n has square factor \ end{aligned} \right.\]

Where \ (P 〝 1p 〝 2 , P (s \) is a different prime number.

It can be seen that \ (\ mu(n) \) is not zero when \ (n \) has no square factor.

\(\ mu \) is also a product function.

Nature

Mobius function has the following properties:

\[\sum_{d|n}\mu(d)=\epsilon(n)=[n=1] \]

Using the Dirichlet convolution, i.e

\[\mu*1=\epsilon \]

prove:

\(n=1 \) obviously.

If \ (n > 1 \), set \ (n \) to have \ (s \) different prime factors. Because \ (\ mu(d)\neq0 \) is and only if \ (D \) has no square factor, the index of each prime factor in \ (D \) can only be \ (0 \) or \ (1 \).

If a factor \ (D \) of \ (n \) has \ (\ mu(d)=(-1)^i \), it is composed of \ (i \) different quality factors. Because the total number of quality factors i s \ (s \), there are \ (C ^ i \) factors satisfying the above formula.

So we can convert the original formula into enumeration \ (\ mu(d) \), and use binomial theorem at the same time

\[\sum_{d|n}\mu(d)=\sum_{i=0}^{s}C_s^i\times(-1)^i=\sum_{i=0}^{s}C_s^i\times(-1)^i\times 1^{s-i}=(1+(-1))^s \]

The formula is 1 when \ (s=0 \) is \ (n=1 \), otherwise \ (0 \).

Find Mobius function

Because Mobius function is a product function, linear sieve can be used

int n, cnt, p[A], mu[A];
bool vis[A];

void getmu() {
    mu[1] = 1;
    for (int i = 2; i <= n; i++) {
	if (!vis[i]) mu[i] = -1, p[++cnt] = i;
	for (int j = 1; j <= cnt && i * p[j] <= n; j++) {
	    vis[i * p[j]] = 1;
	    if (i % p[j] == 0) { mu[i * p[j]] = 0; break; }
	    mu[i * p[j]] -= mu[i];
	}
    }
}

M bius inversion formula

Let \ (f(n) \) and \ (g(n) \) be two number theoretic functions.

If any

\[f(n)=\sum\limits_{d|n}g(d) \]

Then there are

\[g(n)=\sum\limits_{d|n}\mu(d)f(\frac{n}{d}) \]

Prove

  • Method 1: make number theory transformation to the original formula

    1. \(\ sum \ limits {d| n} g (d) \) replace \ (f(n) \), i.e

      \[\sum\limits_{d|n}\mu(d)f(\frac{n}{d})=\sum\limits_{d|n}\mu(d)\sum\limits_{k|\frac nd}g(k) \]
    2. Change the sum order to get

      \[\sum\limits_{k|n}g(k)\sum\limits_{d|\frac n k}\mu(\frac nk) \]
    3. Because \ (\ sum \ limits {d| n} \ mu (d) = [n = 1] \), the above formula is equivalent to

      \[\sum\limits_{d|n}[n=k]g(k)=g(n) \]

    Obtain evidence

  • Method 2: using convolution

    The original problem is: known \ (f=g*1 \), proof \ (g=f*\mu \)

    Conversion: \ (f*\mu=g*1*\mu=g*\varepsilon=g \) (\ (1*\mu=\varepsilon \))

    Re certification ==

Small property

\([\gcd(i,j)=1]\Leftrightarrow\sum\limits_{d|\gcd(i,j)}\mu(d)\)

Prove

  • Law 1:

    If \ (n=\gcd(i,j) \), then \ (= \ sum \ limits {d| n} \ mu (d) = [n = 1] = [\ GCD (I, J) = 1] = \) on the right side of the equation

  • Method 2:

    Using unit function violence to break apart: \ ([\ GCD (I, J) = 1] = \ varepsilon (\ GCD (I, J)) = \ sum \ limits {d| \ GCD (I, J)} \ mu (d) \)

Thinking of doing Questions & Application

A series of summation problems can be solved by using Dirichlet convolution. The common practice is to use a Dirichlet convolution to replace part of the summation formula, then change the order of summation, and ultimately reduce the time complexity.

The commonly used convolutions are \ (\ mu*1=\epsilon \) and \ (\ text{Id}=\varphi*1 \).

topic

It's better to focus on the questions, but the questions you do will also be written separately. After all, you need more blogs / huaji

Luogu P2522 [HAOI2011]Problem b

Title Link

My explanation

There are \ (n \) group queries. Each time \ (a,b,c,d,k \) is given, find \ (\ sum \ limits {x = a} ^ {B} \ sum \ limits {y = C} ^ {D} [\ GCD (x, y = k] \)

Set \ (f (n, m) = \ sum \ limits {I = 1} ^ {n} \ sum \ limits {J = 1} ^ {m} [\ GCD (I, j = k] \)

Then according to the principle of inclusion and exclusion, the formula in the topic is transformed into \ (f(b,d)-f(b, c - 1) - f(a - 1,d) + f(a - 1, c - 1) \)

So our next question is how to find the value of \ (f \)

Now simplify the value of \ (f \)

  1. It is easy to get that the original formula is equivalent to $$\ sum \ limits {I = 1} ^ {\ lfloor \ frac {n} {K} \ rfloor} \ sum \ limits {J = 1} ^ {\ lfloor \ frac {m} {K} \ rfloor} [\ GCD (I, J) = 1]$$

  2. Because \ (\ epsilon (n) = \ sum \ limits {d| n} \ mu (d) = [n = 1] \), the original formula can be changed to

    \[\sum\limits_{i=1}^{\lfloor\frac{n}{k}\rfloor}\sum\limits_{j=1}^{\lfloor\frac{m}{k}\rfloor}\sum\limits_{d|gcd(i,j)}\mu(d) \]
  3. Change the enumeration object and change the enumeration order. First enumerate \ (d \), and get

    \[\sum\limits_{d=1}^{\min(n,m)}\mu(d)\sum\limits_{i=1}^{\lfloor\frac{n}{k}\rfloor}[d|i]\sum\limits_{j=1}^{\lfloor\frac{m}{k}\rfloor}[d|j] \]

    That is, when \ (d|i \) and \ (d|j \), \ (d|\gcd(i,j) \)

  4. 1} ^ {\ min (n, m)} \ mu (d) \ lfloor \ frac {n} {d k} \ rfloor \ lfloor\frac{m}{dk}\rfloor$$

At this time, it can be solved by \ (O(n) \), but it can't pass. Because there are many ranges with the same value, it can be done by number theory block

First, preprocess \ (\ mu \), and then divide them into blocks according to number theory, with complexity of \ (O(n+T\sqrt n) \)

My code scores metaphysics every time, looks at the mood of the evaluator, and suggests writing by myself

/*
Author:loceaner
*/
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int A = 1e6 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;

inline int read() {
	char c = getchar(); int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
	return x * f;
}

int n, a, b, c, d, k, cnt, p[A], mu[A], sum[A];
bool vis[A];

void getmu() {
	int MAX = 50010;
	mu[1] = 1;
	for (int i = 2; i <= MAX; i++) {
		if (!vis[i]) mu[i] = -1, p[++cnt] = i;
		for (int j = 1; j <= cnt && i * p[j] <= MAX; j++) {
			vis[i * p[j]] = true;
			if (i % p[j] == 0) break;
			mu[i * p[j]] -= mu[i];
		}
	}
	for (int i = 1; i <= MAX; i++) sum[i] = sum[i - 1] + mu[i];
}

int work(int x, int y) {
	int ans = 0ll;
	int max = min(x, y);
	for (int l = 1, r; l <= max; l = r + 1) {
		r = min(x / (x / l), y / (y / l));
		ans += (1ll * x / (l * k)) * (1ll * y / (l * k)) * 1ll * (sum[r] - sum[l - 1]); 
	}
	return ans;
}

void solve() {
	a = read(), b = read(), c = read(), d = read(), k = read();
	cout << work(b, d) - work(a - 1, d) - work(b, c - 1) + work(a - 1, c - 1) << '\n';
}

signed main() {
	getmu();
	int T = read();
	while (T--) solve();
	return 0;
}

Luogu p3455 [poi2007] zap queries

Title Link

My explanation

There are \ (T \) group queries, each time

\[\sum\limits_{x=1}^{a}\sum\limits_{y=1}^{b}[\gcd(x,y)=d] \]

Because i don't like to use \ (x, y, a, b, d \), i'll replace them with \ (i, j, n, m, k \)

Direct Ganon

\[\begin{align*}&\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}[\gcd(i,j)=k]\\=& \sum\limits_{i=1}^{\lfloor \frac nk\rfloor}\sum\limits_{j=1}^{\lfloor\frac mk\rfloor}[\gcd(i,j)=1]\\=&\sum\limits_{i=1}^{\lfloor \frac nk\rfloor}\sum\limits_{j=1}^{\lfloor\frac mk\rfloor}\sum\limits_{d|\gcd(i,j)}\mu(d)\\=&\sum\limits_{i=1}^{\lfloor \frac nk\rfloor}\sum\limits_{j=1}^{\lfloor\frac mk\rfloor}\sum\limits_{d|i}\sum _{d|j}\mu(d)\\=&\sum\limits_{d=1}^{\min(\lfloor\frac nk\rfloor,\lfloor\frac mk\rfloor)}\mu(d)\sum\limits_{i=1}^{\lfloor \frac nk\rfloor}\sum\limits_{j=1}^{\lfloor\frac mk\rfloor}\sum\limits_{d|i}\sum\limits_{d|j}1\\=&\sum\limits_{d=1}^{\min(\lfloor\frac nk\rfloor,\lfloor\frac mk\rfloor)}\mu(d)\sum\limits_{i=1}^{\lfloor \frac nk\rfloor}\sum\limits_{d|i}1\sum\limits_{j=1}^{\lfloor\frac mk\rfloor}\sum\limits_{d|j}1\\=&\sum\limits_{d=1}^{\min(\lfloor\frac nk\rfloor,\lfloor\frac mk\rfloor)}\mu(d)\lfloor\frac{\lfloor \frac nk\rfloor}d\rfloor\lfloor\lfloor\frac{\frac mk\rfloor}d\rfloor\\=&\sum\limits_{d=1}^{\min(\lfloor\frac nk\rfloor,\lfloor\frac mk\rfloor)}\mu(d)\lfloor\frac n{kd}\rfloor\lfloor\frac m{kd}\rfloor\end{align*} \]

Now you can ask \ (O(n) \) to do this question every time

But we can't run, but obviously we can divide the number theory into blocks, so we can \ (O(\sqrt n) \) answer every question

/*
Author:loceaner
*/
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int A = 5e5 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;

inline int read() {
	char c = getchar(); int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
	return x * f;
}

int n, m, k, mu[A], p[A], sum[A], cnt;
bool vis[A];

void getmu(int n) {
	mu[1] = 1;
	for (int i = 2; i <= n; i++) {
		if (!vis[i]) p[++cnt] = i, mu[i] = -1;
		for (int j = 1; j <= cnt && i * p[j] <= n; j++) {
			vis[i * p[j]] = 1;
			if (i % p[j] == 0) break;
			mu[i * p[j]] -= mu[i];
		}
	}
	for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + mu[i];
}

int solve(int n, int m, int k) {
	int ans = 0, maxn = min(n, m);
	for (int l = 1, r; l <= maxn; l = r + 1) {
		r = min(n / (n / l), m / (m / l));
		ans += (sum[r] - sum[l - 1]) * (n / (k * l)) * (m / (k * l));
	}
	return ans;
}

int main() {
	getmu(50000);
	int T = read();
	while (T--) {
		n = read(), m = read(), k = read();
		cout << solve(n, m, k) << '\n';
	}
	return 0;
}

Logue P1829 [national training team] Crash's digital form / JZPTAB

Title Link

My explanation

seek

\[\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}\text{lcm}(i,j)(\bmod 20101009) \]

It is easy to think that the original formula is equivalent to

\[\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}\frac{i* j}{\gcd(i,j)} \]

Enumeration of the greatest common divisor \ (d \) of \ (i,j \), obviously \ (\ GCD (\ frac id \ frac jd) = 1 \), that is, \ (\ frac id \) and \ (\ frac jd \) are mutually prime

\[\sum\limits_{i=1}^{n}\sum\limits_{j=1}^m\sum\limits_{d|i,d|j,\gcd(\frac id,\frac jd)=1}\frac{i*j}d \]

Transform sum order

\[\sum\limits_{d=1}^{n}d\sum\limits_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum\limits_{j=1}^{\lfloor\frac{m}{d}\rfloor}[\gcd(i,j)=1]i*j \]

Note \ (sum (n, m) = \ sum \ limits {I = 1} ^ {n} \ sum \ limits {J = 1} ^ {m} [\ GCD (I, J) = 1] I * J \)

Simplify it, replace \ ([\ gcd(i,j)=1] \) with \ (\ varepsilon(\gcd(i,j)) \)

\[\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}\sum\limits_{d|\gcd(i,j)}\mu(d)*i*j \]

Convert to enumerating divisor first

\[\sum\limits_{d=1}^{\min(n,m)}\sum\limits_{d|i}^{n}\sum\limits_{d|j}^{m}\mu(d)*i*j \]

If \ (i=i'*d,j=j'*d \), it can be further converted

\[\sum\limits_{d=1}^{\min(n,m)}\mu(d)*d^2*\sum\limits_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum\limits_{j=1}^{\lfloor\frac{m}{d}\rfloor}i*j \]

The first half can process the prefix sum, and the second half can \ (O(1) \). Set

\[Q(n,m)=\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}i*j=\frac{n*(n+1)}{2}*\frac{m*(m+1)}{2} \]

Obviously, \ (O(1) \) can be solved

Up to now

\[sum(n,m)=\sum\limits_{d=1}^{\min(n,m)}\mu(d)*d^2*Q(\lfloor\frac nd \rfloor,\lfloor\frac md\rfloor) \]

It can be solved by number theory in blocks

Bring back to the original formula

\[\sum\limits_{d=1}^{\min(n, m)}d*sum(\lfloor\frac nd \rfloor,\lfloor\frac md\rfloor) \]

It can be solved by number theory and block

And then it's done

/*
Author:loceaner
*/
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define int long long
using namespace std;

const int A = 1e7 + 11;
const int B = 1e6 + 11;
const int mod = 20101009;
const int inf = 0x3f3f3f3f;

inline int read() {
    char c = getchar(); int x = 0, f = 1;
    for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
    for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
    return x * f;
}

bool vis[A];
int n, m, mu[A], p[B], sum[A], cnt;

void getmu() {
    mu[1] = 1;
    int k = min(n, m);
    for (int i = 2; i <= k; i++) {
        if (!vis[i]) p[++cnt] = i, mu[i] = -1;
        for (int j = 1; j <= cnt && i * p[j] <= k; ++j) {
            vis[i * p[j]] = 1;
            if (i % p[j] == 0) break;
            mu[i * p[j]] = -mu[i];
        }
    }
    for (int i = 1; i <= k; i++) sum[i] = (sum[i - 1] + i * i % mod * mu[i]) % mod;
}

int Sum(int x, int y) { 
	return (x * (x + 1) / 2 % mod) * (y * (y + 1) / 2 % mod) % mod; 
}

int solve2(int x, int y) {
    int res = 0;
    for (int i = 1, j; i <= min(x, y); i = j + 1) {
        j = min(x / (x / i), y / (y / i));
        res = (res + 1LL * (sum[j] - sum[i - 1] + mod) * Sum(x / i, y / i) % mod) % mod;
    }
    return res;
}

int solve(int x, int y) {
    int res = 0;
    for (int i = 1, j; i <= min(x, y); i = j + 1) {
        j = min(x / (x / i), y / (y / i));
        res = (res + 1LL * (j - i + 1) * (i + j) / 2 % mod * solve2(x / i, y / i) % mod) % mod;
    }
    return res;
}

signed main() {
    n = read(), m = read();
    getmu();
    cout << solve(n, m) << '\n';
}

GCD of Logu P2257 YY

Title Link

Given \ (n,m \), find the number of tuples \ ((x,y) \), satisfy \ (1\leq x\leq n,1\leq y\leq m \), and \ (gcd(x,y) \) is prime.

\(n,m\leq 10^7 \), with multiple groups of data, at most \ (10 ^ {4} \) groups of data.

The idea is similar to Problem B in the first question. I will not repeat it here, but only give the code ==

#include <cmath> 
#include <cstdio>
#include <cstring> 
#include <iostream>
using namespace std;

const int A = 1e7 + 11; 

inline int read() {
	char c = getchar(); int x = 0, f = 1;
	for ( ; !isdigit(c); c = getchar()) if(c == '-') f = -1; 
	for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
	return x * f;
}

bool vis[A];
long long sum[A];
int prim[A], mu[A], g[A], cnt, n, m;

void get_mu(int n) {
    mu[1] = 1;
    for (int i = 2; i <= n; i++) {
        if (!vis[i]) {
            mu[i] = -1;
            prim[++cnt] = i;
        }
        for (int j = 1; j <= cnt && prim[j] * i <= n; j++) {
            vis[i * prim[j]] = 1;
            if (i % prim[j] == 0) break;
            else mu[prim[j] * i] = - mu[i];
        }
    }
    for (int j = 1; j <= cnt; j++)
        for (int i = 1; i * prim[j] <= n; i++) g[i * prim[j]] += mu[i];
    for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + (long long)g[i];
}

signed main() {
    int t = read();
    get_mu(10000000);
    while (t--) {
        n = read(), m = read();
        if (n > m) swap(n, m);
        long long ans = 0;
        for (int l = 1, r; l <= n; l = r + 1) {
            r = min(n / (n / l), m / (m / l));
            ans += 1ll * (n / l) * (m / l) * (sum[r] - sum[l - 1]);
        }
        cout << ans << '\n';
    }
    return 0;
}

Luogu P3327 [SDOI2015] sum of approximate numbers

Title Link

seek

\[\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}d(ij) \]

\(d(x) \) is the sum of the divisors of \ (x \)

Need to use

\[d(ij)=\sum\limits_{x|i}\sum\limits_{y|j}[\gcd(x,y)=1] \]

Prove that I won't either

And then I'll deduce it myself. I won't repeat it here

/*
Author:loceaner
*/
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int A = 5e5 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;

inline int read() {
	char c = getchar(); int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
	return x * f;
}

bool vis[A];
int n, m, p[A], mu[A], cnt, sum[A];
long long g[A], ans;

void getmu(int n) {
	mu[1] = 1;
	for (int i = 2; i <= n; i++) {
		if (!vis[i]) mu[i] = -1, p[++cnt] = i;
		for (int j = 1; j <= cnt && i * p[j] <= n; j++) {
			vis[i * p[j]] = 1;
			if (i % p[j] == 0) break;
			mu[i * p[j]] -= mu[i];
		}
	}
	for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + mu[i];
	for (int i = 1; i <= n; i++) {
		int ans = 0;
		for (int l = 1, r; l <= i; l = r + 1) {
			r = (i / (i / l));
			ans += 1ll * (r - l + 1) * (i / l);
		}
		g[i] = ans;
	}
}

signed main() {
	int T = read();
	getmu(50000);
	while (T--) {
		n = read(), m = read();
		int maxn = min(n, m);
		ans = 0;
		for (int l = 1, r; l <= maxn; l = r + 1) {
			r = min(n / (n / l), m / (m / l));
			ans += 1ll * (sum[r] - sum[l - 1]) * 1ll * g[n / l] * 1ll * g[m / l];
		}
		cout << ans << '\n';
	}
	return 0;
}

Logue P4449 in the wrath of God

seek

\[\sum_{i=1}^{n}\sum_{j=1}^{m}\gcd(i,j)^k(\bmod 1e9+7) \]

Or direct Gan

\[\begin{align*}&\sum_{i=1}^{n}\sum_{j=1}^{m}\gcd(i,j)^k\\=&\sum_{i=1}^{n}\sum_{j=1}^{m}\sum_{d=1}^{\min(n,m)}d^k[\gcd(i,j)=d]\\=&\sum_{d=1}^{\min(n,m)}d^k\sum_{i=1}^{\lfloor\frac nd\rfloor}\sum_{j=1}^{\lfloor\frac md\rfloor}[\gcd(i,j)=1]\\=&\sum_{d=1}^{\min(n,m)}d^k\sum_{i=1}^{\lfloor\frac nd\rfloor}\sum_{j=1}^{\lfloor\frac md\rfloor}\sum_{x|\gcd(i,j)}\mu(x)\\=&\sum_{d=1}^{\min(n,m)}d^k\sum_{i=1}^{\lfloor\frac nd\rfloor}\sum_{j=1}^{\lfloor\frac md\rfloor}\sum_{x|i,x|j}\mu(x)\\=&\sum_{d=1}^{\min(n,m)}d^k\sum_{x=1}^{\min(\lfloor\frac nd\rfloor,\lfloor\frac md\rfloor)}\mu(x)\sum_{i=1}^{\lfloor\frac nd\rfloor}[x|i]\sum_{j=1}^{\lfloor\frac md\rfloor}[x|j]\\=&\sum_{d=1}^{\min(n,m)}d^k\sum_{x=1}^{\min(\lfloor\frac nd\rfloor,\lfloor\frac md\rfloor)}\mu(x)\lfloor\frac n{dx}\rfloor\lfloor\frac m{dx}\rfloor\end{align*} \]

Let \ (P=dx \), then the original formula is equal to

\[\sum_{P=1}^{\min(n,m)}\lfloor\frac n{P}\rfloor\lfloor\frac m{P}\rfloor\sum_{d|P}d^k\mu(\frac Pd) \]

Obviously, the preceding \ (\ lfloor\frac n{P}\rfloor\lfloor\frac m{P}\rfloor \) part can be solved in blocks.

Now consider the latter part, and make

\[g(n)=\sum_{d|n}d^k\mu(\frac nd) \]

It's easy to get that this function is a product function, so we can sift it linearly and find the prefix sum

And then it's done

/*
Author:loceaner
 Mobius inversion
*/
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define int long long
using namespace std;

const int A = 5e6 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;

inline int read() {
	char c = getchar();
	int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
	return x * f;
}

bool vis[A];
int T, n, m, k, f[A], g[A], p[A], cnt, sum[A];

inline int power(int a, int b) {
	int res = 1;
	while (b) {
		if (b & 1) res = res * a % mod;
		a = a * a % mod, b >>= 1;
	}
	return res;
}

inline int mo(int x) {
	if(x > mod) x -= mod;
	return x;
}

inline void work() {
	g[1] = 1;
	int maxn = 5e6 + 1;
	for (int i = 2; i <= maxn; i++) {
		if (!vis[i]) { p[++cnt] = i, f[cnt] = power(i, k), g[i] = mo(f[cnt] - 1 + mod); }
		for (int j = 1; j <= cnt && i * p[j] <= maxn; j++) {
			vis[i * p[j]] = 1;
			if (i % p[j] == 0) { g[i * p[j]] = g[i] * 1ll * f[j] % mod; break; }
			g[i * p[j]] = g[i] * 1ll * g[p[j]] % mod;
		}
	}
	for (int i = 2; i <= maxn; i++) g[i] = (g[i - 1] + g[i]) % mod;
}

inline int abss(int x) {
	while (x < 0) x += mod;
	return x;
}

signed main() {
	T = read(), k = read();
	work();
	while (T--) {
		n = read(), m = read();
		int maxn = min(n, m), ans = 0;
		for (int l = 1, r; l <= maxn; l = r + 1) {
			r = min(n / (n / l), m / (m / l));
			(ans += abss(g[r] - g[l - 1]) * 1ll * (n / l) % mod * (m / l) % mod) %= mod;
		}
		ans = (ans % mod + mod) % mod;
		cout << ans << '\n';
	}
	return 0;
}

Posted by jmr3460 on Tue, 28 Apr 2020 21:28:32 -0700